BZOJ3786 : 星系探索

由于没有换根操作,所以直接用Splay维护DFS括号序列即可。

对于查询1到x路径和,就是已入栈的减去已出栈的。

子树加相当于区间加。

换父亲相当于一个区间的移动。

 

本题非常卡常数,一开始直接扒3153的代码狂T不止,改写Splay后也是狂T不止,最后把Splay从数组储存改成结构体储存才AC。

 

#include<cstdio>
#define N 200010
typedef long long ll;
struct P{
  int f,son[2],ci,co;ll val,tag,sum;bool is;
  P(){f=son[0]=son[1]=ci=co=val=tag=sum=is=0;}
}T[N];
int n,m,i,x,y,root,a[N],g[N],nxt[N],v[N],ed,st[N],en[N],dfn,w[N];
char ch;
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 addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  T[st[x]=++dfn].val=w[x],T[dfn].is=1;
  for(int i=g[x];i;i=nxt[i])dfs(v[i]);
  T[en[x]=++dfn].val=w[x];
}
inline void add1(int x,ll p){
  if(!x)return;
  T[x].val+=p;T[x].sum+=p*(T[x].ci-T[x].co);T[x].tag+=p;
}
inline void pb(int x){if(T[x].tag)add1(T[x].son[0],T[x].tag),add1(T[x].son[1],T[x].tag),T[x].tag=0;}
inline void up(int x){
  if(T[x].is)T[x].ci=1,T[x].co=0,T[x].sum=T[x].val;else T[x].ci=0,T[x].co=1,T[x].sum=-T[x].val;
  T[x].ci+=T[T[x].son[0]].ci+T[T[x].son[1]].ci;
  T[x].co+=T[T[x].son[0]].co+T[T[x].son[1]].co;
  T[x].sum+=T[T[x].son[0]].sum+T[T[x].son[1]].sum;
}
inline void rotate(int x){
  int y=T[x].f,w=T[y].son[1]==x;
  T[y].son[w]=T[x].son[w^1];
  if(T[x].son[w^1])T[T[x].son[w^1]].f=y;
  if(T[y].f){
    int z=T[y].f;
    if(T[z].son[0]==y)T[z].son[0]=x;
    if(T[z].son[1]==y)T[z].son[1]=x;
  }
  T[x].f=T[y].f;T[x].son[w^1]=y;T[y].f=x;up(y);
}
inline void splay(int x,int w){
  int s=1,i=x,y;a[1]=x;
  while(T[i].f)a[++s]=i=T[i].f;
  while(s)pb(a[s--]);
  while(T[x].f!=w){
    y=T[x].f;
    if(T[y].f!=w){if((T[T[y].f].son[0]==y)^(T[y].son[0]==x))rotate(x);else rotate(y);}
    rotate(x);
  }
  if(!w)root=x;
  up(x);
}
int build(int l,int r,int fa){
  int x=(l+r)>>1;
  T[x].f=fa;
  if(l==r){return up(x),x;}
  if(l<x)T[x].son[0]=build(l,x-1,x);
  if(r>x)T[x].son[1]=build(x+1,r,x);
  return up(x),x;
}
inline int get(int x,int y){
  while(T[x].son[y])x=T[x].son[y];
  return x;
}
inline void add(int x,int p){
  splay(st[x],0);
  splay(en[x],root);
  add1(T[en[x]].son[0],p);
  T[en[x]].val+=p,up(en[x]);
  T[st[x]].val+=p,up(st[x]);
}
inline void move(int x,int y){
  splay(st[x],0);
  int l=get(T[root].son[0],1);
  splay(en[x],0);
  int r=get(T[root].son[1],0);
  splay(l,0);
  splay(r,root);
  int t=T[r].son[0];
  T[r].son[0]=0,up(r),up(l);
  splay(st[y],0);
  r=get(T[root].son[1],0);
  splay(st[y],0);
  splay(r,root);
  T[r].son[0]=t;
  T[t].f=r;
  up(r),up(root);
}
inline ll ask(int x){
  splay(st[x],0);
  return T[T[root].son[0]].sum+T[root].val;
}
int main(){
  read(n);
  for(i=2;i<=n;i++)read(x),addedge(x,i);
  for(i=1;i<=n;i++)read(w[i]);
  dfs(1);
  root=build(1,dfn,0);
  read(m);
  while(m--){
    while(!(((ch=getchar())=='Q')||(ch=='C')||(ch=='F')));read(x);
    if(ch=='F')read(y),add(x,y);
    if(ch=='C')read(y),move(x,y);
    if(ch=='Q')printf("%lld\n",ask(x));
  }
  return 0;
}

  

 

posted @ 2014-12-02 18:15  Claris  阅读(416)  评论(0编辑  收藏  举报