BZOJ3786:星系探索(Splay,括号序)
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
HINT
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。注意w_i>=0
Solution
TMD卡了半天常没卡过去自闭了……
感觉这个题还是很巧妙的。先说下什么是括号序:$DFS$的时候进入一个点将点入队,出这个点的时候再将这个点入队,这个队列就是欧拉序。
所以这个应该怎么做呢?
第一个操作就是根的入队节点到查询的点的入队节点这一段区间的权值和。
第二个操作就是将一个点的入队到出队节点这一段区间(也就是这个点的子树)移动。
第三个操作就是区间打标记……没什么好说的。
$pushdown$的时候需要记录一下这个区间内有几个入队节点几个出队节点再更新。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (200009) 5 #define LL long long 6 using namespace std; 7 8 struct Edge{int to,next;}edge[N<<1]; 9 int n,m,x,y,Root,q[N],q_num; 10 int head[N],num_edge; 11 int Son[N][2],Father[N]; 12 int a[N],Flag[N]; 13 LL Num[N],Sum[N],Val[N],Add[N]; 14 char opt; 15 16 inline int read() 17 { 18 int x=0; char c=getchar(); 19 while (c<'0' || c>'9') c=getchar(); 20 while (c>='0' && c<='9') x=x*10+c-'0', c=getchar(); 21 return x; 22 } 23 24 void add(int u,int v) 25 { 26 edge[++num_edge].to=v; 27 edge[num_edge].next=head[u]; 28 head[u]=num_edge; 29 } 30 31 int Get(int x) {return Son[Father[x]][1]==x;} 32 33 void Pushup(int x) 34 { 35 Num[x]=Num[Son[x][0]]+Num[Son[x][1]]+Flag[x]; 36 Sum[x]=Sum[Son[x][0]]+Sum[Son[x][1]]+Val[x]; 37 } 38 39 void Pushdown(int x) 40 { 41 if (Add[x]) 42 { 43 int ls=Son[x][0], rs=Son[x][1]; 44 Sum[ls]+=Add[x]*Num[ls]; 45 Val[ls]+=Flag[ls]*Add[x]; Add[ls]+=Add[x]; 46 Sum[rs]+=Add[x]*Num[rs]; 47 Val[rs]+=Flag[rs]*Add[x]; Add[rs]+=Add[x]; 48 Add[x]=0; 49 } 50 } 51 52 void Rotate(int x) 53 { 54 int wh=Get(x); 55 int fa=Father[x],fafa=Father[fa]; 56 Pushdown(fa); Pushdown(x); 57 if (fafa) Son[fafa][Son[fafa][1]==fa]=x; 58 Son[fa][wh]=Son[x][wh^1]; Father[fa]=x; 59 if (Son[fa][wh]) Father[Son[fa][wh]]=fa; 60 Son[x][wh^1]=fa; Father[x]=fafa; 61 Pushup(fa); Pushup(x); 62 } 63 64 void Splay(int x,int tar) 65 { 66 for (int fa; (fa=Father[x])!=tar; Rotate(x)) 67 if (Father[fa]!=tar) 68 Rotate(Get(fa)==Get(x)?fa:x); 69 if (!tar) Root=x; 70 } 71 72 int Pre(int x) 73 { 74 Splay(x,0); 75 int now=Son[x][0]; 76 while (Son[now][1]) now=Son[now][1]; 77 return now; 78 } 79 80 int Next(int x) 81 { 82 Splay(x,0); 83 int now=Son[x][1]; 84 while (Son[now][0]) now=Son[now][0]; 85 return now; 86 } 87 88 void Query(int x) 89 { 90 int pre=n<<1|1, nxt=Next(x); 91 Splay(pre,0); 92 Splay(nxt,pre); 93 printf("%lld\n",Sum[Son[nxt][0]]); 94 } 95 96 void Change(int x,int y) 97 { 98 int pre=Pre(x),nxt=Next(x+n); 99 Splay(pre,0); Splay(nxt,pre); 100 int tmp=Son[nxt][0]; 101 Father[Son[nxt][0]]=0; Son[nxt][0]=0; 102 Pushup(Son[Root][1]); Pushup(Root); 103 104 int Nxt=Next(y); 105 Splay(y,0); Splay(Nxt,y); 106 Father[tmp]=Nxt; Son[Nxt][0]=tmp; 107 Pushup(Son[Root][0]); Pushup(Root); 108 } 109 110 void Update(int x,int y) 111 { 112 int pre=Pre(x), nxt=Next(x+n); 113 Splay(pre,0); Splay(nxt,pre); 114 int tmp=Son[nxt][0]; 115 Add[tmp]+=y; 116 Sum[tmp]+=Add[tmp]*Num[tmp]; 117 Val[tmp]+=Flag[tmp]*Add[tmp]; 118 } 119 120 void DFS(int x,int fa) 121 { 122 q[++q_num]=x; 123 for (int i=head[x]; i; i=edge[i].next) 124 if (edge[i].to!=fa) DFS(edge[i].to,x); 125 q[++q_num]=x+n; 126 } 127 128 int Build(int l,int r,int fa) 129 { 130 if (l>r) {return 0;} 131 int mid=(l+r)>>1, now=q[mid]; 132 Father[now]=fa; 133 Son[now][0]=Build(l,mid-1,now); 134 Son[now][1]=Build(mid+1,r,now); 135 Val[now]=(now<=n)?a[now]:-a[now-n]; 136 Pushup(now); return now; 137 } 138 139 int main() 140 { 141 n=read(); 142 for (int i=2; i<=n; ++i) 143 x=read(), add(x,i); 144 for (int i=1; i<=n; ++i) 145 a[i]=read(), Flag[i]=1, Flag[i+n]=-1; 146 q[q_num=1]=n<<1|1; 147 DFS(1,0); 148 q[++q_num]=n+1<<1; 149 Root=Build(1,q_num,0); 150 m=read(); 151 for (int i=1; i<=m; ++i) 152 { 153 opt=getchar(); while (opt<'A' || opt>'Z') opt=getchar(); 154 if (opt=='Q') x=read(), Query(x); 155 if (opt=='C') x=read(), y=read(), Change(x,y); 156 if (opt=='F') x=read(), y=read(), Update(x,y); 157 } 158 }