洛谷P3128 最大流Max Flow 树上差分

梦想的初衷 提交于 2019-11-29 00:49:33

给定一个n5e4n\leq5e4的树,已经m1e5m\leq1e5次操作,每次操作会选择两个点uuvv,使得两点路径上所有的点都加11,求点权的最大值。
直接暴力是O(nm)O(nm)的,这里考虑差分最后再求前缀和。树上的差分分为点差分和边差分,这里是点差分。对uvu,v分别+1+1,然后对lca(u,v)lca(u,v)fa(lca(u,v))fa(lca(u,v))分别1-1,最后一遍dfsdfs处理即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=5e4+7;
vector<int> G[N]; 
int fa[N][18],dep[N];
int cnt[N]; 
void dfs1(int u,int f) {
	dep[u]=dep[f]+1;
	fa[u][0]=f;
	for(int i=1;(1<<i)<=dep[u];i++) 
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(auto &v:G[u])  {
		if(v==f) continue;
		dfs1(v,u);
	}
} 
int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=17;i>=0;i--) {
		if((1<<i)<=dep[x]-dep[y])
			x=fa[x][i];
	}
	if(x==y) return x;
	for(int i=17;i>=0;i--) {
		if(fa[x][i]!=fa[y][i]) {
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
int ans=0;
void dfs2(int u,int fa) {
	for(auto &v:G[u]) {
		if(v==fa) continue;
		dfs2(v,u);
		cnt[u]+=cnt[v];
	}
	ans=max(ans,cnt[u]);
} 
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs1(1,0);
	while(m--) {
		int u,v;
		scanf("%d%d",&u,&v);
		cnt[u]++;
		cnt[v]++;
		int LCA=lca(u,v);
		cnt[LCA]--;
		cnt[fa[LCA][0]]--;
	}
	dfs2(1,0);
	printf("%d\n",ans);
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!