link

给定一棵树,点有点权,边有边权,你每次修改一个点点权或者是修改一个边边权

你一开始在1号点,你每次改节点之后你需要移动到另一个节点,满足这个节点权值减去路径长度最大(下一次从这个节点移动)如果存在相同的收益,选编号最小的节点

你需要输出每次移动到的节点坐标

题解:

处理树上多条路径可以用动态淀粉质

考虑动态淀粉质,对于点分树上每个点开个线段树,下标为点分树子树中的节点,权值为这个点到子节点的收益,同时维护最大值的坐标

对于点权的修改,可以直接在点分树上暴力跳父亲

对于一条边的修改,考虑从这条边连接两个点中点分树上深度较浅的节点向上暴力跳父亲

假设当前我们跳的是 i,我们需要找x和y中哪个点在以 i 为根原树中深度最大,找那个深度大的点,发现这条边的更改影响的点恰好是这个深度较大的点的子树 所以对于每个点分树子树,我们维护一个dfs序,开线段树时按照dfs序存储(注意判断下标还要按照原编号判断),那么这个操作就是一个区间修改

查询时候还是暴力跳父亲,直接查询每个父亲中子树中除了这个点的最大值,就是一个区间查询

注意要减去父亲到这个点的距离,这个可以单点查询查出来

#include <cstdio>
#include <map>
#include <vector>
using namespace std; int n, q, sum, rt, tot;
long long val[100010], ltmp; // 点权
vector<pair<int, long long>> out[100010]; // 假装它是链式前向星
bool vis[100010]; // 构建点分树用的临时数组,最后是true
int sz[100010][20]; // i 在他的点分树深度为 j 的父亲的子树大小, 第二维 0 为构建点分树临时数组
int maxw[100010]; // 构建点分树的临时数组
long long dist[100010]; // 临时的距离数组
int depth[100010]; // 点分树深度
int deep[100010][20]; // i 在以它深度为 j 的点分树父亲为根时的深度
int father[100010][20]; // i 的深度为 j 的父亲
int dfn[100010][20]; // i 在他的点分树深度为 j 的父亲的dfn
vector<int> id[100010]; // 子树中对应的
struct data { int pos, rt; long long val; } tree[10000010]; //线段树
int lc[10000010], rc[10000010], segtot = 0, segrt[100010]; //左右儿子,每个点的线段树根
long long lazy[10000010]; //线段树lazytag void chkmax(int &a, int b) { if (a < b) a = b; } data operator+(const data &a, const data &b)
{
if (a.val != b.val) return a.val > b.val ? a : b;
if (a.rt == -1) return b;
if (b.rt == -1) return a;
return id[a.rt][a.pos - 1] < id[b.rt][b.pos - 1] ? a : b;
} int build(int cl, int cr, int rt)
{
int x = ++segtot;
if (cl != cr)
{
int mid = (cl + cr) / 2;
lc[x] = build(cl, mid, rt), rc[x] = build(mid + 1, cr, rt), tree[x] = tree[lc[x]] + tree[rc[x]];
}
else tree[x].pos = cl, tree[x].rt = rt;
return x;
} void pushdown(int x)
{
tree[lc[x]].val += lazy[x], tree[rc[x]].val += lazy[x];
lazy[lc[x]] += lazy[x], lazy[rc[x]] += lazy[x], lazy[x] = 0;
} void chenge(int x, int cl, int cr, int L, int R, long long val)
{
if (L <= cl && cr <= R) { tree[x].val += val, lazy[x] += val; return; }
pushdown(x);
int mid = (cl + cr) / 2;
if (L <= mid) chenge(lc[x], cl, mid, L, R, val);
if (R > mid) chenge(rc[x], mid + 1, cr, L, R, val);
tree[x] = tree[lc[x]] + tree[rc[x]];
} data chuans(int x, int cl, int cr, int L, int R)
{
if (L > R) return (data){0, -1, -9223372036854775807LL};
if (L <= cl && cr <= R) return tree[x];
pushdown(x);
int mid = (cl + cr) / 2;
if (R <= mid) return chuans(lc[x], cl, mid, L, R);
if (L > mid) return chuans(rc[x], mid + 1, cr, L, R);
return chuans(lc[x], cl, mid, L, R) + chuans(rc[x], mid + 1, cr, L, R);
} void getrt(int x, int fa)
{
sz[x][0] = 1, maxw[x] = 0;
for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
getrt(i.first, x), sz[x][0] += sz[i.first][0], chkmax(maxw[x], sz[i.first][0]);
chkmax(maxw[x], sum - sz[x][0]); if (maxw[x] < maxw[rt]) rt = x;
} void getsz(int x, int fa, int rt)
{
sz[x][depth[rt]] = 1, father[x][depth[rt]] = rt, dfn[x][depth[rt]] = ++tot, id[rt].push_back(x);
for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
getsz(i.first, x, rt), sz[x][depth[rt]] += sz[i.first][depth[rt]];
} void getdis(int x, int fa, int rt)
{
chenge(segrt[rt], 1, sz[rt][depth[rt]], dfn[x][depth[rt]], dfn[x][depth[rt]], val[x] - dist[x]);
for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
dist[i.first] = dist[x] + i.second, deep[i.first][depth[rt]] = deep[x][depth[rt]] + 1, getdis(i.first, x, rt);
} void solve(int x, int d)
{
vis[x] = true, depth[x] = d, tot = 0, getsz(x, 0, x);
segrt[x] = build(1, sz[x][depth[x]], x), dist[x] = 0, deep[x][depth[x]] = 0, getdis(x, 0, x);
for (pair<int, long long> i : out[x]) if (vis[i.first] == false)
sum = sz[i.first][depth[x]], rt = 0, getrt(i.first, 0), solve(rt, d + 1);
} int main()
{
map<pair<int, int>, long long> e;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%lld", &val[i]);
for (int x, y, i = 1; i < n; i++)
{
scanf("%d%d%lld", &x, &y, &ltmp);
out[x].push_back(make_pair(y, ltmp));
out[y].push_back(make_pair(x, ltmp));
if (x > y) swap(x, y);
e[make_pair(x, y)] = ltmp;
}
maxw[0] = sum = n, getrt(1, 0), solve(rt, 1);
int pos = 1;
for (int opt, x, y, t = 1; t <= q; t++)
{
scanf("%d", &opt);
if (opt == 1)
{
scanf("%d%lld", &x, &ltmp);
for (int i = x; i != 0; i = father[i][depth[i] - 1])
chenge(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]], ltmp - val[x]);
val[x] = ltmp;
}
if (opt == 2)
{
scanf("%d%d%lld", &x, &y, &ltmp);
if (x > y) swap(x, y);
long long delta = ltmp - e[make_pair(x, y)];
e[make_pair(x, y)] = ltmp;
if (depth[x] < depth[y]) swap(x, y);
for (int i = y; i != 0; i = father[i][depth[i] - 1])
{
if (deep[y][depth[i]] > deep[x][depth[i]]) { swap(x, y); }
chenge(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]] + sz[x][depth[i]] - 1, -delta);
}
}
data ans = (data){0, -1, -9223372036854775807LL};
for (int i = pos; i > 0; i = father[i][depth[i] - 1])
{
data tmp = chuans(segrt[i], 1, sz[i][depth[i]], 1, dfn[pos][depth[i]] - 1) + chuans(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]] + 1, sz[i][depth[i]]);
tmp.val += chuans(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]], dfn[pos][depth[i]]).val - val[pos];
ans = ans + tmp;
}
printf("%d%c", pos = id[ans.rt][ans.pos - 1], t == q ? '\n' : ' ');
}
return 0;
}

loj2497 [PA2017]Banany(动态淀粉质)的更多相关文章

  1. 动态淀粉质(划掉)题单&简要题解

    简介 动态点分治的思想:还不太清楚诶怎么办. 大概是通过降低树高来降低每次修改和询问的复杂度吧,还可以把树上一个连通块的信息统计到一个点(重心)上.具体实现方式和普通的静态点分治没有太大的区别,只是把 ...

  2. 淀粉质模板 Tree

    Tree 题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 ...

  3. 题解 洛谷 P4695 【[PA2017]Banany】

    考虑用动态点分治来解决像本题这样带修的树上路径问题. 首先对原树进行点分治,建出点分树,在点分树每个节点上用动态开点线段树来维护以该节点为起点,到其点分树子树中每个节点的利润. 查询时只需在点分树上当 ...

  4. 2017-12 CDQZ集训(已完结)

    从联赛活了下来(虽然分数倒一……),接下来要去CDQZ集训啦…… DAY -2 2017-12-16 被老师安排负责一部分同学的住宿以及安排…… 抓紧时间继续学习,LCT真好玩啊真好玩…… 晚上放假了 ...

  5. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  6. 点分治&&动态点分治学习笔记

    突然发现网上关于点分和动态点分的教程好像很少……蒟蒻开篇blog记录一下吧……因为这是个大傻逼,可能有很多地方写错,欢迎在下面提出 参考文献:https://www.cnblogs.com/LadyL ...

  7. 【ZJOI2007】捉迷藏 小小的总结

    2019-01-09 22:56:33 终于终于把这道题目做掉了... 做了两个晚上..不知道为什么自己如此之笨.. 在洛谷上断断续续一共交了24次,感觉自己都要被封号了. 昨天花半个晚上从零开始研究 ...

  8. 洛谷$P$3241 开店 $[HNOI2015]$ 主席树/点分治

    正解:主席树/动态点分治 解题报告: 传送门! $umm$淀粉质的话要是动态的我还不会$QAQ$,,,所以先写下主席树的题解昂$QwQ$ 题目大意是说,给定一棵树,树上每个点都有个值,然后有若干个询问 ...

  9. [Updating]点分治学习笔记

    Upd \(2020/2/15\),又补了一题 LuoguP2664 树上游戏 \(2020/2/14\),补了一道例题 LuoguP3085 [USACO13OPEN]阴和阳Yin and Yang ...

随机推荐

  1. LINK : fatal error LNK1104: cannot open file "mfc42d.lib"

    VC++6.0上建立了个基于MFC应用程序,在编译时候没出现错误,但在LINK的是时候出现这样的错误:Linking...LINK : fatal error LNK1104: cannot open ...

  2. C#HTML解析利器HtmlAgilityPack

    HtmlAgilityPack是一个开源的解析HTML元素的类库,最大的特点是可以通过XPath来解析HMTL,如果您以前用C#操作过XML,那么使用起HtmlAgilityPack也会得心应手.目前 ...

  3. js 数字游戏

    在某网站看到一道js题,觉得有点意思 Some numbers have funny properties. For example: 89 --> 8¹ + 9² = 89 * 1 695 - ...

  4. p2598 [ZJOI2009]狼和羊的故事

    传送门 分析 起点向狼连边,羊向终点连边,边权均为inf 每个点向它四联通的点连边权萎1的边 跑最小割即可 代码 #include<iostream> #include<cstdio ...

  5. 洛谷 P3112 [USACO14DEC]后卫马克Guard Mark

    题目描述 Farmer John and his herd are playing frisbee. Bessie throws the frisbee down the field, but it' ...

  6. Greeplum 系列(四) 实战

    Greeplum 系列(四) 实战 表结构 (1) 拉链表结构 create table public.member_fatdt0 ( member_id varchar(64), phoneno v ...

  7. ScreenCapturePro2 for Joomla_3.4.7-tinymce4x

    1.1. 与Joomla_3.4.7-tinymce4x整合 示例下载:Joomla_3.4.7,   1.1.1. 添加screencapture文件夹   1.1.2. 2.添加插件文件夹 路径: ...

  8. (转载)get和 post方法的不同

    HTTP的Get/Post请求区别归纳 1. get是从服务器上获取数据,post是向服务器传送数据.g et 和 post只是一种传递数据的方式,get也可以把数据传到服务器,他们的本质都是发送请求 ...

  9. javascript的caller,callee,call,apply[转]

    在提到上述的概念之前,首先想说说javascript中函数的隐含参数:arguments Arguments 该对象代表正在执行的函数和调用它的函数的参数. [function.]arguments[ ...

  10. Alpha冲刺 - (8/10)

    队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 进一步优化代码,结合自己负责的部分修改功能 代码规范完整 ...