首先用树状数组维护dfs序来快速支持一个点子树大小的询问。
每次删掉一个叶子时,从根开始往叶子走,显然只有$2size[x]leq size[father]$的点的父亲才有可能换重儿子。
从根开始往下,找到最高的满足条件的点,从那个点开始继续迭代,每次点数至少减小一半,所以迭代只有$O(log n)$次。
时间复杂度$O(nlog^2n)$。
#include<cstdio> const int N=200010; int n,m,x,i,ch[N][2],size[N],f[N],d[N],son[N],top[N],st[N],en[N],q[N],dfn,bit[N];long long ans; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int x,int p){for(;x<=n;x+=x&-x)bit[x]+=p;} inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;} inline int getsize(int x){ if(!x)return 0; return ask(en[x])-ask(st[x]-1); } void dfs(int x){ size[x]=1; for(int i=0;i<2;i++){ int y=ch[x][i]; if(!y)continue; f[y]=x;d[y]=d[x]+1; dfs(y),size[x]+=size[y]; if(size[y]>size[son[x]])son[x]=y; } ans+=son[x]; } void dfs2(int x,int y){ q[st[x]=++dfn]=x;top[x]=y; if(son[x])dfs2(son[x],y); for(int i=0;i<2;i++){ int o=ch[x][i]; if(!o||o==son[x])continue; dfs2(o,o); } en[x]=dfn; } inline int up(int x,int k){ while(1){ if(st[x]-st[top[x]]>=k)return q[st[x]-k]; k-=st[x]-st[top[x]]+1; x=f[top[x]]; } } inline void recal(int x){ if(!x)return; ans-=son[x]; int t=0; for(int i=0;i<2;i++){ int y=ch[x][i],w=getsize(y); if(w>t)t=w; } if(!t)son[x]=0; else if(getsize(son[x])!=t){ if(getsize(ch[x][0])==t)son[x]=ch[x][0]; else son[x]=ch[x][1]; } ans+=son[x]; } inline void remove(int x){ add(st[x],-1); int lim=d[x],o=lim; while(1){ int l=1,r=o,mid,t=0,s=getsize(up(x,o)); while(l<=r)if(getsize(up(x,mid=(l+r)>>1))*2<=s)l=(t=mid)+1;else r=mid-1; recal(f[up(x,t)]); if(!o)return; o=t; } } int main(){ while(~scanf("%d",&n)){ if(!n)return 0; for(dfn=ans=0,i=1;i<=n;i++)size[i]=son[i]=bit[i]=0; for(i=1;i<=n;i++)read(ch[i][0]),read(ch[i][1]); dfs(1); dfs2(1,1); printf("%lld ",ans); for(i=1;i<=n;i++)add(i,1); for(read(m);m--;printf("%lld ",ans))read(x),remove(x); } return 0; }