1009F.Dominant Indices (树上启发式合并)
给出n个点。
对每个点,询问它的子树中:
假设距离它为d的点有x个,求最大的x,并输出d。
如果有多个x相同,输出最小的d。
题解:
树上启发式合并。
用数组f维护当前节点子树内第i层的节点数。
数组Max维护当前节点子树内最大的节点数的层。
数组Ans维护当前节点的答案。
在转移时,Max和Ans可以直接从重儿子转移。
时间复杂度\(O(nlogn)\)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
int c[maxn];
vector<int> g[maxn];
int f[maxn];
int L[maxn],R[maxn],id[maxn];
int dep[maxn];
int size[maxn];
int tot;
int son[maxn];
int n,m;
int ans[maxn];
int Max[maxn];
void dfs1 (int x,int pre) {
dep[x]=dep[pre]+1;
size[x]=1;
L[x]=++tot;
id[tot]=x;
for (int y:g[x]) {
if (y==pre) continue;
dfs1(y,x);
size[x]+=size[y];
if (size[son[x]]<size[y]) son[x]=y;
}
R[x]=tot;
}
void cal (int x,int pre) {
f[dep[x]]++;
if (f[dep[x]]>Max[x]) {
Max[x]=f[dep[x]];
ans[x]=dep[x];
}
else if (f[dep[x]]==Max[x]) {
ans[x]=min(ans[x],dep[x]);
}
for (int y:g[x]) {
if (y==son[x]||y==pre) continue;
for (int j=L[y];j<=R[y];j++) {
int z=id[j];
f[dep[z]]++;
if (f[dep[z]]>Max[x]) {
Max[x]=f[dep[z]];
ans[x]=dep[z];
}
else if (f[dep[z]]==Max[x]) {
Max[x]=f[dep[z]];
ans[x]=min(ans[x],dep[z]);
}
}
}
}
void dfs2 (int x,int pre,int kp) {
for (int y:g[x]) {
if (y==son[x]||y==pre) continue;
dfs2(y,x,0);
}
if (son[x]) {
dfs2(son[x],x,1);
ans[x]=ans[son[x]];
Max[x]=Max[son[x]];
}
cal(x,pre);
if (!kp) for (int i=L[x];i<=R[x];i++) f[dep[id[i]]]=0;
}
int main () {
scanf("%d",&n);
for (int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1,0);
dfs2(1,0,1);
for (int i=1;i<=n;i++) printf("%d\n",ans[i]-dep[i]);
}