1. 程式人生 > >【bzoj3786】【星系探索】【dfs序+splay】

【bzoj3786】【星系探索】【dfs序+splay】

n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保證操作合法。

題解:

         用splay維護樹的括號序列.

         l[x],r[x]分別表示點x的進棧位置和出棧位置.

         把左括號的位置賦成正值,右括號的位置賦成負值.

         那查詢根到x的鏈和就是[l[1],l[x]]的和.

         修改x所在子樹就是修改[l[x],r[x]]這一段序列.

         子樹移動就是找到這棵子樹代表的這段序列,然後插到一個點後面.

         這些都可以用splay來處理.

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010 
#define LL long long 
using namespace std;
int point[N],n,m,x,y,next[N<<1],a[N],cnt,top=1,l[N],r[N];
int st[N],root;
char ch;
struct use{
  int st,en;
}e[N<<1];
struct node{
  int g,v,fa,lg,rg,c[2];
  LL s,ad;
}t[N];
inline void ins(int x,int y){
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].st=x;e[cnt].en=y;
}
inline int read(){
  int x(0);char ch=getchar();
  while (ch<'0'||ch>'9') ch=getchar();
  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x;
}
void dfs(int x,int fa){
  l[x]=++top;t[top].g=1;t[top].v=a[x];
  for (int i=point[x];i;i=next[i])
    if (e[i].en!=fa)
      dfs(e[i].en,x);
  r[x]=++top;t[top].g=2;t[top].v=-a[x];
}
inline void update(int k){
  int a=t[k].c[0],b=t[k].c[1];
  t[k].s=t[a].s+t[b].s+(LL)t[k].v;
  t[k].lg=t[a].lg+t[b].lg+(t[k].g==1);
  t[k].rg=t[a].rg+t[b].rg+(t[k].g==2);
}
void build(int k,int l,int r){
  if (l>r) return;
  int mid=(l+r)>>1;
  if (k) t[k].c[mid>k]=mid;
  t[mid].fa=k;
  build(mid,l,mid-1);
  build(mid,mid+1,r);
  update(mid); 
}
inline void paint(int x,int c){
  if (t[x].g==1) t[x].v+=c;
  if (t[x].g==2) t[x].v-=c;
  t[x].s+=(LL)(t[x].lg-t[x].rg)*c;
  t[x].ad+=c;
}
inline void pushdown(int x){
  int a=t[x].c[0],b=t[x].c[1];
  if (t[x].ad){
    if (a) paint(a,t[x].ad);
    if (b) paint(b,t[x].ad); 
  }
  t[x].ad=0;
}
inline void rotate(int x,int &k){
  int y=t[x].fa,z=t[y].fa,a,b;
  if (t[y].c[0]==x) a=0;else a=1;b=a^1;
  if (y==k) k=x;
  else{
    if (t[z].c[0]==y) t[z].c[0]=x;
    else t[z].c[1]=x;
  }
  t[x].fa=z;t[y].fa=x;t[t[x].c[b]].fa=y;
  t[y].c[a]=t[x].c[b];t[x].c[b]=y;
  update(y);update(x);
}
inline void splay(int x,int &k){
  int top(0);
  st[++top]=x;
  for (int i=x;t[i].fa;i=t[i].fa) st[++top]=t[i].fa;
  while(top--) pushdown(st[top]);
  while (x!=k){
    int y=t[x].fa,z=t[y].fa;
    if (y!=k){
      if ((t[y].c[0]==x)^(t[z].c[0]==y)) rotate(x,k);
      else rotate(y,k);
    }
    rotate(x,k);
  }
}
inline int left(int x){
  while (t[x].c[1]) x=t[x].c[1];
  return x;
}
inline int right(int x){
  while (t[x].c[0]) x=t[x].c[0];
  return x;
} 
inline int split(int x,int y){
  int a,b;
  splay(x,root);a=left(t[x].c[0]);
  splay(y,root);b=right(t[y].c[1]);
  splay(a,root);splay(b,t[a].c[1]);
  return t[b].c[0];
}
inline void query(int k){
  int x=split(l[1],l[k]);
  printf("%lld\n",t[x].s); 
} 
inline void add(int k,int y){
  int x=split(l[k],r[k]);
  paint(x,y);
} 
inline void change(int u,int v){
  int a,b,x=split(l[u],r[u]);
  a=root;b=t[a].c[1];t[b].c[0]=0;
  update(b);update(a);
  a=l[v];splay(a,root);
  b=right(t[a].c[1]);
  splay(b,t[a].c[1]);
  t[b].c[0]=x;t[x].fa=b;
  update(b);update(a);
}
int main(){
 // freopen("a.in","r",stdin);
  //freopen("a.out","w",stdout);
  n=read();
  for (int i=2;i<=n;i++){
    x=read();ins(x,i);ins(i,x);
  }
  for (int i=1;i<=n;i++) a[i]=read();
  dfs(1,0);
  top++;root=(1+top)>>1;
  build(0,1,top);
  //for (int i=1;i<=top;i++) cout<<c[i][0]<<' '<<c[i][1]<<endl;
  m=read();
  for (int i=1;i<=m;i++){
    for(ch=getchar();ch<'A'||ch>'Z';ch=getchar());
    if (ch=='Q'){
      x=read();
      query(x);
    }
    if (ch=='F'){
      x=read();y=read();
      add(x,y);
    }
    if (ch=='C'){
      x=read();y=read();
      change(x,y);
    }
  }
}