[图论神器]树链剖分

用途

解决树上问题,一般来说如果有查询又有询问就非常的复杂。如果用LCA你更改了树就会原地爆炸,因而树链剖分的用途就显现出来了。虽然板子多,还不如打暴力

预备概念

重儿子:父亲结点的所有儿子结点中,子树拥有结点数最多的结点。轻儿子:父亲结点除了重儿子以外的所有儿子。重边:父亲结点与重儿子的连边。轻边:父亲结点与轻儿子的连边。重链:所有重边所组成的一条链。

变量声明

fa[u]:保存点u的父亲结点d[u]:保存点u的深度size[u]:保存以u为根节点的子树的结点个数son[u]:保存点u的重儿子top[u]:保存点u所在重链的顶端结点id[u]:保存点u进行重新编号后的新的编号

操作

首先进行一次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;
	}
}
原文地址:https://www.cnblogs.com/lover-fucker/p/13566652.html