其实发现我们一定会在最大子树中选择一个子树接到最小的子树上。
假设我们二分这个答案为 x x x,所有子树中最大值为 m x mx mx,次大值为 s u b m x submx submx,最小值为 m n mn mn,则答案显然不可能小于 s u b m x submx submx,且我们选出来的子树大小 d e l t a delta delta 必须满足 m x − d e l t a ≤ x mx-delta\leq x mx−delta≤x且 m n + d e l t a ≤ x mn+delta\leq x mn+delta≤x,也就是 m x − x ≤ d e l t a ≤ x − m n mx-x \leq delta \leq x-mn mx−x≤delta≤x−mn。显然就是区间存在性问题。
用平衡树维护一下子树内有哪些可以选择的 s i z siz siz,注意当最大子树在父亲方向的时候,我们需要对全局维护平衡树,同时对当前点到根的路径专门维护一棵平衡树,因为在删掉 u u u的时候,这些点的 s i z siz siz全部都要减掉 s i z [ u ] siz[u] siz[u]。
于是就能 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)做这道题了,空间复杂度 O ( n ) O(n) O(n)
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+7;
namespace SBT{
cs int N=::N<<2|1;
int lc[N],rc[N];
int val[N],c[N],siz[N],rsiz[N];
int tot,dl[N],tp,q[N],qc[N],qn;
inline int newnode(int v,int ct){
int u=tp?dl[tp--]:++tot;
lc[u]=rc[u]=0;val[u]=v,c[u]=siz[u]=ct,rsiz[u]=1;
return u;
}
inline void pushup(int u){
rsiz[u]=rsiz[lc[u]]+rsiz[rc[u]]+1;
siz[u]=siz[lc[u]]+siz[rc[u]]+c[u];
}
inline void Zig(int &u){
int v=lc[u];lc[u]=rc[v];rc[v]=u;
pushup(u),pushup(v);u=v;
}
inline void Zag(int &u){
int v=rc[u];rc[u]=lc[v];lc[v]=u;
pushup(u),pushup(v);u=v;
}
cs double alpha=0.55;
inline void ins(int &u,int v,int ct=1){
if(!u){u=newnode(v,ct);return ;}
siz[u]+=ct;
if(val[u]==v)c[u]+=ct;
else if(v<val[u]){
ins(lc[u],v,ct);
if(rsiz[lc[u]]>rsiz[u]*alpha)Zig(u);
}
else {
ins(rc[u],v,ct);
if(rsiz[rc[u]]>rsiz[u]*alpha)Zag(u);
}
pushup(u);
}
inline void del(int &u,int v){
if(!u)return ;
if(val[u]==v){
if(c[u]>1)--c[u],--siz[u];
else if(!lc[u]||!rc[u])dl[++tp]=u,u=lc[u]|rc[u];
else if(rsiz[lc[u]]<rsiz[rc[u]])Zag(u),del(u,v);
else Zig(u),del(u,v);
if(u)pushup(u);
return ;
}
if(v<val[u])del(lc[u],v);
else del(rc[u],v);pushup(u);
}
inline int Rank(int u,int v){//count <=v
int ans=0;
while(u){
if(val[u]==v)return ans+siz[lc[u]]+c[u];
if(val[u]<v)ans+=siz[lc[u]]+c[u],u=rc[u];
else u=lc[u];
}
return ans;
}
inline int range(int rt,int l,int r){return Rank(rt,r)-Rank(rt,l-1);}
void inorder_dfs(int u){
if(lc[u])inorder_dfs(lc[u]);
q[++qn]=val[u],qc[qn]=c[u];dl[++tp]=u;
if(rc[u])inorder_dfs(rc[u]);
}
inline void Join(int &u,int &v){
if(rsiz[u]<rsiz[v])std::swap(u,v);
qn=0;inorder_dfs(v);v=0;
for(int re i=1;i<=qn;++i)ins(u,q[i],qc[i]);
}
}
using SBT::ins;
using SBT::del;
using SBT::range;
using SBT::Join;
int n;
int el[N],nxt[N<<1],to[N<<1],ect;
inline void adde(int u,int v){
nxt[++ect]=el[u],el[u]=ect,to[ect]=v;
nxt[++ect]=el[v],el[v]=ect,to[ect]=u;
}
int fa[N],siz[N];
void pre_dfs(int u){
siz[u]=1;for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=fa[u]){pre_dfs(v);siz[u]+=siz[v];}
}
int rt[N],rt_all,rt_path,root;
int ans[N];
inline bool check(int u,int mxson,int mn,int mx,int lim){
int l=mx-lim,r=lim-mn;
if(l>r)return false;
if(mxson==fa[u]){
int s1=range(rt_all,l,r);
int s2=range(rt[u],l,r);
int s3=range(rt_path,l+siz[u],r+siz[u]);
return s1+s3>s2;
}
else {
return range(rt[mxson],l,r)>0;
}
}
void dfs_solve(int u){
del(rt_all,siz[u]);
if(u!=root)ins(rt_path,siz[u]);
int mn=1e9,mx=0,submx=0,mxson=0;
for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]]){
int siz_v=v==fa[u]?n-siz[u]:siz[v];
if(v!=fa[u])dfs_solve(v);
mn=std::min(siz_v,mn);
if(siz_v>mx){
submx=mx,mxson=v;
mx=siz_v;
}else if(siz_v>submx)submx=siz_v;
}
ins(rt_all,siz[u]);ins(rt[u],siz[u]);
if(u!=root)del(rt_path,siz[u]);
if(mxson==fa[u])for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=fa[u])Join(rt[u],rt[v]);
int l=submx==0?mx:submx,r=mx,mid;
while(l<r)check(u,mxson,mn,mx,mid=l+r>>1)?r=mid:l=mid+1;ans[u]=l;
if(mxson!=fa[u])for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=fa[u])Join(rt[u],rt[v]);
}
#ifdef zxyoi
#undef zxyoi
#endif
signed main(){
#ifdef zxyoi
freopen("winter.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("winter.in","r",stdin);freopen("winter.out","w",stdout);
#endif
#endif
n=gi();
for(int re i=1;i<=n;++i){
int f=gi(),u=gi();
if(!f)root=u;
else adde(fa[u]=f,u);
}pre_dfs(root);
for(int re i=1;i<=n;++i)ins(rt_all,siz[i]);
dfs_solve(root);
for(int re i=1;i<=n;++i)cout<<ans[i]<<"\n";
return 0;
}