题目链接:Codeforces - F. Dominant Indices
题目大意:1号节点为根,每个点的子树,某个深度节点最多的层数。如果多个相等,输出深度小的。
我们肯定由深度开始枚举,对每个子树线段树合并,然后权值线段树上面求值即可。
当然这道题也可 dsu on tree,但是常数比权值线段树大。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e6+10;
int n,dep[N],m,res[N];
vector<int> v[N],g[N];
int rt[N],mx[N<<5],lc[N<<5],rc[N<<5],cnt;
void dfs(int x,int fa){
dep[x]=dep[fa]+1; m=max(m,dep[x]); v[dep[x]].push_back(x);
for(int i=0;i<g[x].size();i++){
if(g[x][i]!=fa) dfs(g[x][i],x);
}
}
void change(int &p,int l,int r,int x){
if(!p) p=++cnt;
if(l==r){mx[p]++; return ;}
int mid=l+r>>1;
if(x<=mid) change(lc[p],l,mid,x);
else change(rc[p],mid+1,r,x);
mx[p]=max(mx[lc[p]],mx[rc[p]]);
}
int ask(int p,int l,int r){
if(!p) return 0;
if(l==r) return l; int mid=l+r>>1;
if(mx[lc[p]]==mx[p]) return ask(lc[p],l,mid);
else return ask(rc[p],mid+1,r);
}
int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;
if(l==r){mx[x]+=mx[y]; return x;}
int mid=l+r>>1;
lc[x]=merge(lc[x],lc[y],l,mid);
rc[x]=merge(rc[x],rc[y],mid+1,r);
mx[x]=max(mx[lc[x]],mx[rc[x]]);
return x;
}
signed main(){
cin>>n;
for(int i=1,x,y;i<n;i++)
scanf("%d %d",&x,&y),g[x].push_back(y),g[y].push_back(x);
dfs(1,1);
for(int i=m;i>=1;i--){
for(int j=0;j<v[i].size();j++){
int now=v[i][j]; change(rt[now],1,m,i);
for(int k=0;k<g[now].size();k++){
int to=g[now][k];
if(dep[to]>dep[now]) merge(rt[now],rt[to],1,m);
}
res[now]=ask(rt[now],1,m)-i;
}
}
for(int i=1;i<=n;i++) printf("%d\n",res[i]);
return 0;
}