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

来源:互联网 发布:linux怎么进入命令界面 编辑:程序博客网 时间:2024/06/04 23:00

Description

物理学家小C的研究正遇到某个瓶颈。

他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球。主星球没有依赖星球。

我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c.

对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的。并且从星球a出发只能直接到达它的依赖星球b.

每个星球i都有一个能量系数wi.C想进行若干次实验,第i次实验,他将从飞船上向星球di发射一个初始能量为0的能量收集器,能量收集器会从星球di开始前往主星球,并收集沿途每个星球的部分能量,收集能量的多少等于这个星球的能量系数。

但是星系的构成并不是一成不变的,某些时刻,星系可能由于某些复杂的原因发生变化。

有些时刻,某个星球能量激发,将使得所有依赖于它的星球以及他自己的能量系数均增加一个定值。还有可能在某些时刻,某个星球的依赖星球会发生变化,但变化后依然满足依赖关系是无环的。

现在小C已经测定了时刻0时每个星球的能量系数,以及每个星球(除了主星球之外)的依赖星球。接下来的m个时刻,每个时刻都会发生一些事件。其中小C可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。

Input

第一行一个整数n,表示星系的星球数。

接下来n-1行每行一个整数,分别表示星球2-n的依赖星球编号。

接下来一行n个整数,表示每个星球在时刻0时的初始能量系数wi.

接下来一行一个整数m,表示事件的总数。

事件分为以下三种类型。

(1)"Q di"表示小C要开始一次实验,收集器的初始位置在星球di.

(2)"C xi yi"表示星球xi的依赖星球变为了星球yi.

(3)"F pi qi"表示星球pi能量激发,常数为qi.

Output

对于每一个事件类型为Q的事件,输出一行一个整数,表示此次实验的收集器最终能量。

Sample Input

3
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2

Sample Output

9
15
25

HINT

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);    }  }}

0 0
原创粉丝点击