bzoj3786星系探索(splay维护dfs序)
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
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2
Sample Output
15
25
解题思路:
这道题假如没有换根操作,那么就是一入栈出栈序的裸题,也就是,对于子树更改节点,在入栈出栈序上这个点入栈处加入操作,在出栈处取消操作(区间加和就好)。而查询操作,则是查询某个点入栈序的前缀和。验证这个方法的正确性:如果这个点i是点j的子树中的点,那么就能查询到加入操作,而查询不到取消操作。那么就是说,如果查询前缀时,若同时查询到了入栈和出栈,那么操作就会被取消。
对于这道题,区间和可以被认为是子树权值和,只要子树中同时有入栈和出栈,那么权值上就没有这个点。
那么就维护一下入栈出栈序。
用splay维护入栈出栈序,splay的中序遍历就是入栈出栈序。
考虑操作Q,查询入栈出栈序的前缀和。
那么就是将这个点的入栈位置旋转到根,答案就是左子树权值和+根权。
考虑操作C,将一段入栈出栈序插入到另一段入栈出栈序之中。
那么就先将这段入栈出栈序的前驱旋转到根,再将后继旋转至根的儿子。
那么我们就将这棵树像挤痘痘一样挤了出来。
然后将根摘除并pushup两次愈合伤口。
再旋转出要加的位置栽上,再pushup两次使其无缝连接^_^
考虑操作F,将子树加权。
懒惰标记旋转时下传即可。
注意:
1.由于入栈出栈序一一对应,取消操作只要是加入操作的相反数即可。
2.子树内求和懒惰标记时总和为入栈个数。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define lll tr[spc].ch[0] 5 #define rrr tr[spc].ch[1] 6 #define ls ch[0] 7 #define rs ch[1] 8 typedef long long lnt; 9 const int N=300000; 10 struct pnt{ 11 int hd; 12 int ind; 13 int oud; 14 lnt vl; 15 }p[N]; 16 struct ent{ 17 int twd; 18 int lst; 19 }e[N]; 20 struct trnt{ 21 int ch[2]; 22 int fa; 23 lnt val; 24 lnt sum; 25 lnt wgt; 26 lnt ctr; 27 lnt lzt; 28 lnt fst; 29 lnt chr; 30 }tr[N],stdtr; 31 int n,m,cnt,siz; 32 int root; 33 int ic; 34 int plc[N]; 35 int dnf[N]; 36 char cmd[10]; 37 int vls(int x) 38 { 39 if(x==0||x==ic+1) 40 return 0; 41 return (p[dnf[x]].ind==x)?1:-1; 42 } 43 bool whc(int spc) 44 { 45 return tr[tr[spc].fa].rs==spc; 46 } 47 void new_point(int spc,int i) 48 { 49 tr[spc]=stdtr; 50 int cmdlp=vls(i); 51 plc[i]=spc; 52 tr[spc].chr=dnf[i]; 53 tr[spc].val=p[dnf[i]].vl*cmdlp; 54 tr[spc].ctr=cmdlp; 55 return ; 56 } 57 void ade(int f,int t) 58 { 59 cnt++; 60 e[cnt].twd=t; 61 e[cnt].lst=p[f].hd; 62 p[f].hd=cnt; 63 return ; 64 } 65 void dfs(int x) 66 { 67 p[x].ind=++ic; 68 dnf[ic]=x; 69 for(int i=p[x].hd;i;i=e[i].lst) 70 dfs(e[i].twd); 71 p[x].oud=++ic; 72 dnf[ic]=x; 73 return ; 74 } 75 void pushup(int spc) 76 { 77 tr[spc].wgt=tr[lll].wgt+tr[rrr].wgt+1; 78 tr[spc].sum=tr[lll].sum+tr[rrr].sum+tr[spc].val; 79 tr[spc].fst=tr[lll].fst+tr[rrr].fst+tr[spc].ctr; 80 return ; 81 } 82 void FFT(lnt spc,lnt k) 83 { 84 if(!spc) 85 return ; 86 tr[spc].lzt+=k; 87 tr[spc].sum+=k*tr[spc].fst; 88 tr[spc].val+=k*tr[spc].ctr; 89 return ; 90 } 91 void pushdown(int spc) 92 { 93 if(tr[spc].lzt) 94 { 95 FFT(lll,tr[spc].lzt); 96 FFT(rrr,tr[spc].lzt); 97 tr[spc].lzt=0; 98 } 99 return ; 100 } 101 void build(int l,int r,int &spc,int f) 102 { 103 if(l>r) 104 return ; 105 int mid=(l+r)>>1; 106 spc=++siz; 107 new_point(spc,mid); 108 tr[spc].fa=f; 109 build(l,mid-1,lll,spc); 110 build(mid+1,r,rrr,spc); 111 pushup(spc); 112 return ; 113 } 114 void rotate(int spc) 115 { 116 int f=tr[spc].fa; 117 pushdown(f); 118 pushdown(spc); 119 bool k=whc(spc); 120 tr[f].ch[k]=tr[spc].ch[!k]; 121 tr[spc].ch[!k]=f; 122 tr[tr[f].fa].ch[whc(f)]=spc; 123 tr[spc].fa=tr[f].fa; 124 tr[f].fa=spc; 125 tr[tr[f].ch[k]].fa=f; 126 pushup(spc); 127 pushup(f); 128 return ; 129 } 130 void splay(int spc,int f) 131 { 132 while(tr[spc].fa!=f) 133 { 134 int ft=tr[spc].fa; 135 if(tr[ft].fa==f) 136 { 137 rotate(spc); 138 break; 139 } 140 if(whc(ft)^whc(spc)) 141 rotate(spc); 142 else 143 rotate(ft); 144 rotate(spc); 145 } 146 if(!f) 147 root=spc; 148 return ; 149 } 150 int place(int spc,int cmd)//0 qianqu 151 { 152 if(tr[spc].ch[cmd]) 153 { 154 spc=tr[spc].ch[cmd]; 155 while(tr[spc].ch[1-cmd]) 156 spc=tr[spc].ch[1-cmd]; 157 return spc; 158 } 159 while(whc(spc)==(bool)cmd) 160 spc=tr[spc].fa; 161 return tr[spc].fa; 162 } 163 int main() 164 { 165 scanf("%d",&n); 166 for(int i=2;i<=n;i++) 167 { 168 int x; 169 scanf("%d",&x); 170 ade(x,i); 171 } 172 for(int i=1;i<=n;i++) 173 scanf("%lld",&p[i].vl); 174 scanf("%d",&m); 175 dfs(1); 176 build(0,ic+1,root,0); 177 while(m--) 178 { 179 scanf("%s",cmd); 180 if(cmd[0]=='Q') 181 { 182 int x; 183 scanf("%d",&x); 184 splay(plc[p[x].ind],0); 185 printf("%lld\n",tr[root].val+tr[tr[root].ls].sum); 186 }else if(cmd[0]=='C') 187 { 188 int x,y; 189 scanf("%d%d",&x,&y); 190 splay(place(plc[p[x].ind],0),0); 191 splay(place(plc[p[x].oud],1),root); 192 int tmp=tr[tr[root].rs].ls; 193 tr[tr[root].rs].ls=0; 194 pushup(tr[root].rs); 195 pushup(root); 196 splay(plc[p[y].ind],0); 197 splay(place(plc[p[y].ind],1),root); 198 tr[tr[root].rs].ls=tmp; 199 tr[tmp].fa=tr[root].rs; 200 pushup(tr[root].rs); 201 pushup(root); 202 }else 203 { 204 lnt x,y; 205 scanf("%lld%lld",&x,&y); 206 splay(place(plc[p[x].ind],0),0); 207 splay(place(plc[p[x].oud],1),root); 208 int spc=tr[tr[root].rs].ls; 209 tr[spc].lzt+=y; 210 tr[spc].sum+=tr[spc].fst*y; 211 tr[spc].val+=tr[spc].ctr*y; 212 } 213 214 } 215 return 0; 216 }