树链剖分
暂存的题目集,后面再做整理
先对树跑一遍dfs获得其dfs序,然后对以某个结点为根的子树进行操作,转化为dfs序上对区间的操作,这个过程可以使用线段树完成
欧拉序:跑dfs的时候,将第一次出现该点的时候,记录为1,第二次出现时记录为-1,对树上链的操作就转化成前缀和了,过程可用线段树维护区间和
询问子树的和等操作等价于询问区间\([intime_u,outtime_u]\)的和
习题:
P3178 [HAOI2015]树上操作 :跑一遍dfs记录欧拉序和用线段树维护前缀和
P3833 [SHOI2012]魔法树 : 欧拉序,对于\(u \to v\)这一条链的修改操作,设\(p = LCA(u , v)\), 那么就是树上差分,先对区间\([intime_p , intime_u]\)和区间\([intime_p , intime_v]\)进行区间\(+val\),然后对\(intime_p\)进行单点修改\(-val\)。
P2590 [ZJOI2008]树的统计 树剖+ 单点修改+ 区间最值 + 区间求和
P3384 【模板】轻重链剖分/树链剖分 :两遍dfs,然后用线段树进行维护即可
const int N = 1e5 + 5;
vector<vector<int>>graph(N);
int mod;
int a[N];
int fa[N], dep[N], siz[N], son[N];
void dfs1(int u, int f) {
fa[u] = f; dep[u] = dep[f] + 1;
siz[u] = 1;
int maxsize = -1;
for (auto g : graph[u]) {
if (g == f) continue;
dfs1(g, u);
siz[u] += siz[g];
if (siz[g] > maxsize) maxsize = siz[g], son[u] = g;
}
return;
}
int tim, dfn[N], top[N], weight[N];
void dfs2(int u, int t) {
dfn[u] = ++tim;
top[u] = t;
weight[tim] = a[u];
if (!son[u]) return;
dfs2(son[u], t);
for (auto g : graph[u]) {
if (g == fa[u] || g == son[u]) continue;
dfs2(g, g);
}
return;
}
struct Tree {
long long sum, tag;
int lr, rs, mid;
};
Tree tree[N << 2];
void pushUp(int rt) {
tree[rt].sum = (tree[rt << 1].sum + tree[rt << 1 | 1].sum) % mod;
return;
}
void buildTree(int rt, int lr, int rs) {
tree[rt].lr = lr; tree[rt].rs = rs;
if (lr == rs) {
tree[rt].sum = weight[lr];
return;
}
int mid = tree[rt].mid = lr + rs >> 1;
buildTree(rt << 1, lr, mid);
buildTree(rt << 1 | 1, mid + 1, rs);
pushUp(rt);
return;
}
void pushDown(int rt) {
if (tree[rt].tag == 0) return;
long long tag = tree[rt].tag;
tree[rt].tag = 0;
tree[rt << 1].sum = (tree[rt << 1].sum + tag * (tree[rt << 1].rs - tree[rt << 1].lr + 1)) % mod;
tree[rt << 1 | 1].sum = (tree[rt << 1 | 1].sum + tag * (tree[rt << 1 | 1].rs - tree[rt << 1 | 1].lr + 1)) % mod;
(tree[rt << 1].tag += tag) %= mod;
(tree[rt << 1 | 1].tag += tag) %= mod;
return;
}
void update(int rt, int lr, int rs, int val) {
if (lr > tree[rt].rs || tree[rt].lr > rs) return;
if (tree[rt].lr >= lr && tree[rt].rs <= rs) {
(tree[rt].sum += 1ll * val * (tree[rt].rs - tree[rt].lr + 1ll)) %= mod;
(tree[rt].tag += val) %= mod;
return;
}
pushDown(rt);
if (tree[rt].mid >= lr) update(rt << 1, lr, rs, val);
if (tree[rt].mid < rs) update(rt << 1 | 1, lr, rs, val);
pushUp(rt);
return;
}
long long query(int rt, int lr, int rs) {
if (tree[rt].rs < lr || tree[rt].lr > rs) return 0;
if (tree[rt].lr >= lr && tree[rt].rs <= rs) return tree[rt].sum;
pushDown(rt);
long long res = 0;
if (tree[rt].mid >= lr) res += query(rt << 1, lr, rs);
if (tree[rt].mid < rs) res += query(rt << 1 | 1, lr, rs);
res %= mod;
return res;
}
void updateSon(int x, int val) {
update(1, dfn[x], dfn[x] + siz[x] - 1, val);
}
int querySon(int x) {
return query(1, dfn[x], dfn[x] + siz[x] - 1);
}
void updateChain(int u, int v, int val) {
val %= mod;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
update(1, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
if (dep[u] > dep[v]) std::swap(u, v);
update(1, dfn[u] + , dfn[v], val);
return;
}
int queryChain(int u, int v) {
long long res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
res += query(1, dfn[top[u]], dfn[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v]) std::swap(u, v);
res += query(1, dfn[u], dfn[v]);
return res % mod;
}
P3038 [USACO11DEC]Grass Planting G LCA + 树链剖分 + 线段树 注意更新的时候要减去LCA的值
CF343D Water Tree :套路题,根据要求操作即可
CF165D Beard Graph :将边权转化成点权,然后模拟
P4315 月下“毛景树” :先转化成点权,查询的时候把LCA存下来,然后修改链之后,再把LCA改回去,询问修改都按照这样的思路
UVA1674 闪电的能量 Lightning Energy Report :T到炸裂,多组注意清空
P3950 部落冲突 :边权设置为1,维护边权即可
P4114 Qtree1 SP375 QTREE - Query on a tree SP375 QTREE - Query on a tree原题链接 :注意清空LCA数组等
CF396C On Changing Tree : \(x - (dep_v - dep_u) * k = (-dep_v *k )+ (x + dep_u * k)\) 第一项的操作等价于\(-dep_v * \sum k\) 拿两个树状数组维护一下即可
SP3978 DISQUERY - Distance Query 树链剖分+线段树维护区间极值
CF383C Propagating tree 用两个树状数组维护深度为奇数和偶数的点即可(dfs + BIT / 线段树)
-
P2486 [SDOI2011]染色 树链剖分加线段树,只是询问的时候合并区间注意一下即可
-
CF916E Jamie and Tree dfs序+ 线段树 + LCA ,由于换根,所以需要对根进行讨论,讨论方法见题解区
-
P3979 遥远的国度 树剖 + 线段树 询问的时候讨论一下根跟当前询问子根的关系即可,具体看题解 \(QAQ\)
作者:cherish.
出处:https://home.cnblogs.com/u/cherish-/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。