树 上 差分

改天补坑矩阵的差分

树上差分:

模型:树上多次区间修改.

差分适用于修改多而询问少的情况

类型:1.边差分 2.点差分

边差分:把边的路径全部+x,把两个点的\(u\)\(v的lca\)算出来,然后在差分数组\(dlt[u]+=x,dlt[v]+=x\),在\(dlt[lca(u,v)]-=2x\)

点差分:多次把点的点权加x,最后问点权最大为多少,这就是P3128 USACO15DEC

做法在\(dlt[lca(u,v)]-=x\)并把\(dit[fa(lca(u,v))]-=x\). 因为\(lca(u,v)\)也在u...v这条路径上,它同样需要被加x.回溯的时候会从u和v两个方向都给lca(u,v)加一个x,而它只能加一个,因此\(dlt[lca(u,v)]-=x\)。而\(lca(u,v)\)的爸爸则根本无法被加,在\(lca(u,v)\)已经只加一个x了,因此\(dlt[fa[lca(u,v)]]-=x\)就能让\(lca(u,v)\)的爸爸不加x

#include<cstdio>
#include<iostream> 
#define re register
#define ll long long 
#define maxn 50005
using namespace std;
struct edge{
	int to,next;
}e[maxn<<2];
inline int read(){
	int s=0;
	char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') s=s*10+c-'0',c=getchar();
	return s;
}
int head[maxn],power[maxn],n,m,d[maxn],fa[maxn][22],ans,tot;
inline void add(int u,int v){e[++tot].to = v;e[tot].next = head[u];head[u] = tot;}
inline void dfs(int u,int fath){
	d[u]=d[fath]+1,fa[u][0]=fath;
	for (re int i=0;fa[u][i];++i) fa[u][i+1]=fa[fa[u][i]][i];
	for (re int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if (v!=fath) dfs(v,u);
	}
	return ;
}
inline int lca(int u,int v){
	if(d[u] > d[v]) std::swap(u,v);
	for(re int i = 20;i >= 0;i--) if(d[u] <= d[v] - (1<<i)) v = fa[v][i];
	if(u == v) return u;
	for(re int i = 20;i >= 0;i--) if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
	return fa[u][0];
}
inline void get(int u,int f){
	for(re int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == f) continue;
		get(v,u);
		power[u] += power[v];
	}
	ans = std::max(ans,power[u]);
}
int main(){
	n = read();m = read();
	int x,y;
	for(re int i = 1;i <= n - 1;i++){
		x = read(), y = read();
		add(x,y); add(y,x);
	}
	dfs(1,0);
	for(re int i = 1;i <= m;i++){
		x = read(), y = read();
		int LCA = lca(x,y);
		++power[x];++power[y];--power[LCA];--power[fa[LCA][0]];
	}
	get(1,0);
	printf("%d\n",ans);
	return 0;
}

改日补个边差分 咕咕咕

posted @ 2020-07-28 20:02  INFP  阅读(114)  评论(1编辑  收藏  举报