BZOJ3553 : [Shoi2014]三叉神经树

设val[i]为i连出去的树突中输出值为0的个数

如果val[x]<=1,输出值为1,否则输出值为0

修改x就相当于val[f[i]]++或者val[f[i]]--

 

用Link-cut Tree维护这棵树,

每个节点维护val[x]、size[x](子树大小)、cnt1[x](子树里val[x]==1的个数)、cnt2[x](子树里val[x]==2的个数)

 

以val[f[i]]--为例:

设x=f[i]

access(x)取出x到根这条链

如果val[x]!=2,那么x的输出值不变,直接修改x即可

如果val[x]==2,那么影响到的肯定是一段连续的2以及最开头的2之前的那个点y

如果从根节点开始到x一直都是2,那么直接把这条链打上全部修改为1的标记即可

否则,因为这个具有单调性,所以可以二分这个y,

二分时方便起见二分深度,

对于当前二分到的mid,把深度为mid的点t splay上来

那么只要检验t的右子树是否符合cnt2[]==size[]就可以了

找到y之后splay(y),然后y的右子树里打上全部修改为1的标记,再把y单点修改即可

 

总复杂度$O(q\log^2n)$

 

#include<cstdio>

#define N 500010

int f[N*3],son[N][2],size[N],val[N],cnt1[N],cnt2[N],tag[N],a[N];

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 swap(int&a,int&b){int c=a;a=b;b=c;}

inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}

inline void same1(int x,int p){

  if(!x)return;

  val[x]=tag[x]=p;

  if(p==1)cnt1[x]=size[x],cnt2[x]=0;else cnt2[x]=size[x],cnt1[x]=0;

}

inline void pb(int x){if(tag[x])same1(son[x][0],tag[x]),same1(son[x][1],tag[x]),tag[x]=0;}

inline void up(int x){

  size[x]=size[son[x][0]]+size[son[x][1]]+1;

  cnt1[x]=cnt1[son[x][0]]+cnt1[son[x][1]]+(val[x]==1);

  cnt2[x]=cnt2[son[x][0]]+cnt2[son[x][1]]+(val[x]==2);

}

inline void rotate(int x){

  int y=f[x],w=son[y][1]==x;

  son[y][w]=son[x][w^1];

  if(son[x][w^1])f[son[x][w^1]]=y;

  if(f[y]){

    int z=f[y];

    if(son[z][0]==y)son[z][0]=x;

    if(son[z][1]==y)son[z][1]=x;

  }

  f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);

}

inline void splay(int x){

  int s=1,i=x,y;a[1]=i;

  while(!isroot(i))a[++s]=i=f[i];

  while(s)pb(a[s--]);

  while(!isroot(x)){

    y=f[x];

    if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}

    rotate(x);

  }

  up(x);

}

inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}

inline int kth(int x,int k){

  while(1){

    if(k==size[son[x][0]]+1)return x;

    if(k<=size[son[x][0]])x=son[x][0];else k-=size[son[x][0]]+1,x=son[x][1];

  }

}

inline void dec(int x){

  access(x);splay(x);

  if(x==1||val[x]!=2){val[x]--;up(x);return;}

  if(size[x]==cnt2[x]){same1(x,1);return;}

  int y=0,l=1,r=size[x]-1,mid,t=x;

  while(l<=r){

    mid=(l+r)>>1;

    splay(t=kth(t,mid));

    if(cnt2[son[t][1]]==size[son[t][1]])y=t,r=mid-1;else l=mid+1;

  }

  splay(y);same1(son[y][1],1);val[y]--;up(y);

}

inline void inc(int x){

  access(x);splay(x);

  if(x==1||val[x]!=1){val[x]++;up(x);return;}

  if(size[x]==cnt1[x]){same1(x,2);return;}

  int y=0,l=1,r=size[x]-1,mid,t=x;

  while(l<=r){

    mid=(l+r)>>1;

    splay(t=kth(t,mid));

    if(cnt1[son[t][1]]==size[son[t][1]])y=t,r=mid-1;else l=mid+1;

  }

  splay(y);same1(son[y][1],2);val[y]++;up(y);

}

int n,i,x,j,g[N*3],nxt[N*6],v[N*6],ed,q,show[N*3];

inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}

void dfs(int x,int pre){

  f[x]=pre;

  if(x>n)return;

  for(int i=g[x];i;i=nxt[i])if(v[i]!=pre){

    dfs(v[i],x);

    if(!show[v[i]])val[x]++;

  }

  show[x]=val[x]<=1;

}

int main(){

  for(read(n),i=1;i<=n;i++)for(size[i]=1,j=0;j<3;j++)read(x),add(i,x),add(x,i);

  for(i=n+1;i<=3*n+1;i++)read(show[i]);

  dfs(1,0);

  read(q);

  while(q--){

    read(x);

    if(show[x])inc(f[x]);else dec(f[x]);show[x]^=1;

    splay(1);

    printf("%d\n",val[1]<=1);

  }

  return 0;

}

  

 

你可能感兴趣的:(ZOJ)