BZOJ4389 : ZYB and Trees

Link-Cut Tree维护。

每个点x维护以下信息:

v:这个点的点权

s:实链上的信息和

st:子树信息和(不包括链上)

sa:子树+链上的信息和

as:所有虚儿子的sa的和

则有

s[x]=v[x]+s[son[x][0]]+s[son[x][1]]

st[x]=as[x]+st[son[x][0]]+st[son[x][1]]

sa[x]=s[x]+st[x]

在access以及link的时候,涉及到虚实边的切换,在这个时候顺带维护一下as即可。

查询以x为根时y子树信息和的时候,将x作为根,然后access(y),此时答案=as[y]+v[y]。

时间复杂度$O(m\log n)$。

 

#include<cstdio>
#define N 200010
typedef long long ll;
int n,m,i,op,x,y,z;
int f[N],son[N][2],tmp[N],c[N];bool rev[N];
ll v[N],s[N],mx[N],tc[N],ta[N];
ll st[N],sa[N],as[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 umax(ll&a,ll b){if(a<b)a=b;}
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 rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
inline void col1(int x,ll y){
  if(!x)return;
  v[x]=mx[x]=tc[x]=y;
  s[x]=y*c[x];
  ta[x]=0;
  sa[x]=s[x]+st[x];
}
inline void add1(int x,ll y){
  if(!x)return;
  v[x]+=y;
  s[x]+=y*c[x];
  mx[x]+=y;
  if(tc[x])tc[x]+=y;else ta[x]+=y;
  sa[x]=s[x]+st[x];
}
inline void pb(int x){
  if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;
  if(tc[x])col1(son[x][0],tc[x]),col1(son[x][1],tc[x]),tc[x]=0;
  if(ta[x])add1(son[x][0],ta[x]),add1(son[x][1],ta[x]),ta[x]=0;
}
inline void up(int x){
  s[x]=mx[x]=v[x];c[x]=1;
  st[x]=as[x];
  for(int i=0;i<2;i++){
    int y=son[x][i];
    if(y){
      c[x]+=c[y];
      s[x]+=s[y];
      umax(mx[x],mx[y]);
      st[x]+=st[y];
    }
  }
  sa[x]=s[x]+st[x];
}
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;else 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;tmp[1]=i;
  while(!isroot(i))tmp[++s]=i=f[i];
  while(s)pb(tmp[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);
    if(son[x][1])as[x]+=sa[son[x][1]];
    if(son[x][1]=y)as[x]-=sa[y];
    up(x);
  }
}
inline void makeroot(int x){access(x);splay(x);rev1(x);}
inline void link(int x,int y){
  makeroot(x);
  makeroot(y);
  as[y]+=sa[x];
  f[x]=y;
  access(x);
}
inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
inline void cut(int x,int y){makeroot(x);cutf(y);}
inline void col(int x,int y,int z){makeroot(x);access(y);splay(y);col1(y,z);}
inline void add(int x,int y,int z){makeroot(x);access(y);splay(y);add1(y,z);}
inline ll chainsum(int x,int y){makeroot(x);access(y);splay(y);return s[y];}
inline ll chainmax(int x,int y){makeroot(x);access(y);splay(y);return mx[y];}
inline ll subtreesum(int x,int y){makeroot(x);access(y);splay(y);return as[y]+v[y];}
int main(){
  read(n);
  for(i=1;i<=n;i++)read(x),v[i]=s[i]=mx[i]=sa[i]=x,c[i]=1;
  for(i=2;i<=n;i++)read(x),link(x,i);
  read(m);
  while(m--){
    read(op),read(x),read(y);
    if(op==1)read(z),add(x,y,z);
    if(op==2)read(z),col(x,y,z);
    if(op==3)printf("%lld\n",subtreesum(x,y));
    if(op==4)printf("%lld\n",chainmax(x,y));
    if(op==5)printf("%lld\n",chainsum(x,y));
    if(op==6)link(x,y);
    if(op==7)cut(x,y);
  }
  return 0;
}

  

posted @ 2016-01-06 00:50  Claris  阅读(592)  评论(1编辑  收藏  举报