传送门
调了半天,是读优里面异或忘记打括号了。
维护三种平衡树:
①全局平衡树(不包含根到当前节点的链)
②路径平衡树(包含从根到当前点的路径上的点,除了根节点。因为根节点没有父亲节点)
③每个节点维护一个子树中存在的子树
s
i
z
siz
siz的平衡树
然后删掉一个点后,形成的森林里面的
s
i
z
siz
siz值有一个
m
x
mx
mx,
m
n
mn
mn,
s
u
b
m
x
submx
submx(次大),
m
x
mx
mx对应一个
m
x
s
o
n
mxson
mxson。
首先二分的答案
x
x
x一定大等于
s
u
b
m
x
submx
submx,因为只能移动一个。
令移动的子树大小为
d
e
l
t
a
delta
delta,那么有:
x
≥
m
x
−
d
e
l
t
a
,
x
≥
m
n
+
d
e
l
t
a
⇒
m
x
−
x
≤
d
e
l
t
a
≤
x
−
m
n
x \geq mx-delta,x \geq mn+delta \Rightarrow mx-x \le delta \le x-mn
x≥mx−delta,x≥mn+delta⇒mx−x≤delta≤x−mn
于是在区间里面找是否存在这样一个
d
e
l
t
a
delta
delta即可。
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using namespace std;
cs int N=1e5+10;
int n,u,f,root,rt_all,rt_path,rt[N],fa[N],ans[N];
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return x;
}
namespace SBT{
cs double alpha=0.55;
cs int M=N<<2|1;
int lc[M],rc[M],tot;
int val[M],c[M],siz[M],rsiz[M];
int dl[M],tp,q[M],qc[M],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;
}
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,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;
namespace GRAPH{
int Head[N],Next[N<<1],V[N<<1],siz[N],cnt=0;
inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
void pre_dfs(int u){
siz[u]=1;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(v!=fa[u]) pre_dfs(v),siz[u]+=siz[v];
}
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]) return (range(rt_all,l,r)-range(rt[u],l,r)+range(rt_path,l+siz[u],r+siz[u]))>0;
else return range(rt[mxson],l,r)>0;
}
void solve(int u){
del(rt_all,siz[u]);
if(u!=root) ins(rt_path,siz[u]);
int mn=n+1,mx=0,submx=0,mxson=0;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]){
int siz_v=v==fa[u]?n-siz[u]:siz[v];
if(v!=fa[u]) solve(v);mn=min(mn,siz_v);
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 i=Head[u],v=V[i];i;v=V[i=Next[i]])
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 i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(v!=fa[u]) Join(rt[u],rt[v]);
}
}
using GRAPH::add;
int main(){
n=read();
for(int re i=1;i<=n;++i){
f=read(),u=read();
if(!f) root=u;
else add(fa[u]=f,u),add(u,f);
}GRAPH::pre_dfs(root);
for(int re i=1;i<=n;++i) ins(rt_all,GRAPH::siz[i]);
GRAPH::solve(root);
for(int re i=1;i<=n;++i) printf("%d\n",ans[i]);
}