洛谷P3038 [USACO11DEC]牧草种植Grass Planting

题目

树链剖分或者树上差分

树链剖分只能对点进行操作,所以把边权化为点权。树上化边权为点权的一般操作是把边权赋到深度较深的点里。

然后用树链剖分+线段树更改权值路径和+单点查询即可解决该问题。

#include <bits/stdc++.h>
#define N 4001011
#define ls l, mid, root << 1
#define rs mid + 1, r, root << 1 | 1
using namespace std;
struct edg {
	int to, nex;
}e[N * 4];
int lin[N], dep[N], fat[N], siz[N], son[N], data[N], dfn[N], top[N], temp[N], cnt, n, m, tot;//data[i]表示i的点权。 
int tree[N << 2], lazy[N << 2];
inline void add(int f, int t)//默认边权为0 
{
	e[++cnt].nex = lin[f];
	e[cnt].to = t;
	lin[f] = cnt;
}
void dfs1(int now, int fa)
{
	dep[now] = dep[fa] + 1;
	fat[now] = fa;
	siz[now] = 1;
	for (int i = lin[now]; i; i = e[i].nex)
	{
		int to = e[i].to;
		if (to == fa) continue;
		dfs1(to, now);
		siz[now] += siz[to];
		if (siz[to] > siz[son[now]])
			son[now] = to;
	}
}
void dfs2(int now, int tes) //求出dfs序, 树链剖分求lca 
{
	dfn[now] = ++tot;//dfn是dfs序
	top[now] = tes;
	if (!son[now]) return;
	dfs2(son[now], tes);
	for (int i = lin[now]; i; i = e[i].nex)//找重链
	{
		int to = e[i].to;
		if (to == fat[now] || to == son[now]) continue;
		dfs2(to, to);
	}
}	
inline void pushup(int root) {tree[root] = tree[root << 1] + tree[root << 1 | 1];}
void build(int l, int r, int root)
{	
	if (l == r)
	{
		tree[root] = 0;
		return;
	}
	int mid = (l + r) >> 1;
	build(ls), build(rs);
	pushup(root);
}	
void pushdown(int l, int r, int root)
{
	int mid = (l + r) >> 1;
 	if (lazy[root])
 	{
 		lazy[root << 1] += lazy[root];
 		lazy[root << 1 | 1] += lazy[root];
 		tree[root << 1] += lazy[root] * (mid - l + 1);
 		tree[root << 1 | 1] += lazy[root] * (r - mid);
 		lazy[root] = 0;
 	}
}
int query(int pos, int l, int r, int root)
{
 	if (l == r)    
 		return tree[root];
 	int res = 0, mid = (l + r) >> 1;
 	pushdown(l, r, root);
 	if (pos <= mid)
 		res += query(pos, ls);
 	else  
 		res += query(pos, rs);
 	return res;
}
void update(int ql, int qr, int add, int l, int r, int root)
{
	if (ql <= l && r <= qr)
	{
		tree[root] += (r - l + 1) * add;
		lazy[root] += add;
		return;
	}
	pushdown(l, r, root);
	int mid = (l + r) >> 1;
	if (ql <= mid)
		update(ql, qr, add, ls);
	if (qr > mid)
		update(ql, qr, add, rs);
	pushup(root);
}
void U(int x, int y)
{
	while (top[x] != top[y])//找他们的lca
	{
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		update(dfn[top[x]], dfn[x], 1, 1, n, 1);
		x = fat[top[x]];
	}
	if (dep[x] > dep[y])
		swap(x, y);
	update(dfn[x] + 1, dfn[y], 1, 1, n, 1);
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1, a, b; i < n; i++) {scanf("%d%d", &a, &b), add(a, b), add(b, a);}
	dfs1(1, 0);
	dfs2(1, 1);
	build(1, n, 1);
	while (m--)
	{
		char flag; int a, b;
		cin >> flag >> a >> b;
		if (flag == 'P')
			U(a, b);
		else
		{
			if (dep[a] < dep[b]) swap(a, b);
			printf("%d
", query(dfn[a], 1, n, 1));
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/liuwenyao/p/11804051.html