CodeForces 1009F.Dominant Indices【树上启发式合并】

传送门

题意

给定一棵以 11 为根,nn 个节点的树。设 d(u,x)d(u,x) 为 uu 子树中到 uu 距离为 xx 的节点数。
对于每个点,求一个最小的 kk,使得 d(u,k)d(u,k) 最大。

题解

和那个数颜色的题是一样的,就是一道标准的 dsu on tree 的模板题。当练手了。

代码

#include <bits/stdc++.h>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=1e6+10;
const int M=1e6+10;
int n,siz[N],dep[N],son[N],ans[N],cnt[N],Son,maxd;
vector<int> g[N];
 
void predfs(int u,int fa){
	siz[u]=1;dep[u]=dep[fa]+1;
	for(int v:g[u]){
		if(v==fa) continue;
		predfs(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
 
void add(int u,int fa,int val){
	cnt[dep[u]]+=val;
	if(cnt[dep[u]]>cnt[maxd]||cnt[dep[u]]==cnt[maxd]&&dep[u]<maxd) maxd=dep[u];
	for(int v:g[u]) if(v!=fa&&v!=Son) add(v,u,val);
}
 
void dfs(int u,int fa,bool keep){
	for(int v:g[u]){
		if(v==fa||v==son[u]) continue;
		dfs(v,u,false);
	}
	if(son[u]) dfs(son[u],u,true);
	Son=son[u];
	add(u,fa,1);
	ans[u]=maxd;
	if(!keep) Son=0,add(u,fa,-1),maxd=0;
}
 
int main(){
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	predfs(1,0);
	dfs(1,0,true);
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]-dep[i]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12611886.html