用途
解决树上问题,一般来说如果有查询又有询问就非常的复杂。如果用LCA你更改了树就会原地爆炸,因而树链剖分的用途就显现出来了。虽然板子多,还不如打暴力
预备概念
变量声明
操作
首先进行一次dfs求出除id,top外的数组。
void dfs1(int step,int fa1){
size[step] = 1;
for (int i = 0;i < G[step].size();i ++){
int u = G[step][i];
if (u != fa1){
fa[u] = step;
dep[u] = dep[step] + 1;
dfs1(u,step);
size[step] += size[u];
if (size[u] > size[son[step]])
son[step] = u;
}
}
}
然后,在进行一次dfs求出id,top
void dfs2(int step,int fa1){
id[step] = ++ cnt;
w1[cnt] = w[step];
top[step] = fa1;
if (!son[step])
return ;
dfs2(son[step],fa1);
for (int i = 0;i < G[step].size();i ++){
int u = G[step][i];
if (u != fa[step] && u != son[step])
dfs2(u,u);
}
}
然后我就不知道该怎么写了…
由于很久以前的东西(2019年起稿,快一年了),不想写了,所以直接贴代码,保存一下模板吧
void solve1(int u,int v,int x){//区间修改
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]])
swap(u,v);
update(1,x,id[top[u]],id[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v])
swap(u,v);
update(1,x,id[u],id[v]);
}
int solve2(int u,int v){//区间查询
int ans = 0;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]])
swap(u,v);
ans = (ans + find(1,id[top[u]],id[u])) % p;
u = fa[top[u]];
}
if (dep[u] > dep[v])
swap(u,v);
ans = (ans + find(1,id[u],id[v])) % p;
return ans;
}
线段树维护
void build (int i,int l,int r){
tree[i].l = l,tree[i].r = r;
if(l == r){
tree[i].x = w1[l];
return ;
}
int mid = (l + r) / 2;
build (i * 2,l,mid);
build (i * 2 + 1,mid + 1,r);
tree[i].x = (tree[i * 2].x + tree[i * 2 + 1].x) % p;
}
void pushdown(int x){
tree[x * 2].x = (tree[x * 2].x + (tree[x * 2].r - tree[x * 2].l + 1) * lazy[x] % p) % p;
tree[x * 2 + 1].x = (tree[x * 2 + 1].x + (tree[x * 2 + 1].r - tree[x * 2 + 1].l + 1) * lazy[x] % p) % p;
lazy[x * 2] = (lazy[x * 2] + lazy[x]) % p;
lazy[x * 2 + 1] = (lazy[x * 2 + 1] + lazy[x]) % p;
lazy[x] = 0;
}
void update(int i,int x,int l,int r){
if (tree[i].l > r || tree[i].r < l)
return ;
if (tree[i].l >= l && tree[i].r <= r){
lazy[i] = (lazy[i] + x) % p;
tree[i].x = (tree[i].x + (tree[i].r - tree[i].l + 1) * x) % p;
return ;
}
if (lazy[i])
pushdown(i);
update(i * 2,x,l,r);
update(i * 2 + 1,x,l,r);
tree[i].x = (tree[i * 2].x + tree[i * 2 + 1].x) % p;
}
int find(int i,int l,int r){
if (tree[i].l > r || tree[i].r < l)
return 0;
if (tree[i].l >= l && tree[i].r <= r)
return tree[i].x;
else {
if (lazy[i])
pushdown(i);
int sum = 0;
sum = (sum + find(i * 2,l,r)) % p;
sum = (sum + find(i * 2 + 1,l,r)) % p;
return sum;
}
}