BZOJ 3786 星系探索
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.保证操作合法。
1 #include<cstdio> 2 #include<cstdlib> 3 using namespace std; 4 5 typedef long long ll; 6 #define maxn 200010 7 int n,m,cnt,stack[maxn],dfn[maxn]; 8 int next[maxn],side[maxn],toit[maxn]; 9 10 inline int Abs(int a) { if (a < 0) return -a; return a; } 11 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 16 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 struct SPLAY 21 { 22 ll key[maxn],sum[maxn],inc[maxn]; 23 int size[maxn],sz[maxn],sf[maxn],ch[maxn][2],fa[maxn],root; 24 25 inline int find(int rest) 26 { 27 int now = root; 28 while (true) 29 { 30 if (rest == size[ch[now][0]]+1) break; 31 else if (rest > size[ch[now][0]]+1) rest -= size[ch[now][0]]+1,now = ch[now][1]; 32 else now = ch[now][0]; 33 } 34 return now; 35 } 36 37 inline void pushdown(int now) 38 { 39 int lc = ch[now][0],rc = ch[now][1]; 40 if (inc[now]) 41 { 42 sum[now] += (ll)sz[now]*inc[now]-(ll)sf[now]*inc[now]; 43 key[now] += (now <= n?1:-1)*inc[now]; 44 if (lc) inc[lc] += inc[now]; if (rc) inc[rc] += inc[now]; 45 inc[now] = 0; 46 } 47 } 48 49 inline void updata(int now) 50 { 51 int lc = ch[now][0],rc = ch[now][1]; 52 if (lc) pushdown(lc); if (rc) pushdown(rc); 53 size[now] = size[lc] + size[rc] + 1; 54 sz[now] = sz[lc] + sz[rc] + (now <= n); 55 sf[now] = sf[lc] + sf[rc] + (now > n); 56 sum[now] = sum[lc] + sum[rc] + key[now]; 57 } 58 59 inline int build(int l,int r) 60 { 61 int mid = (l + r) >> 1,now = (dfn[mid]<0)*n+Abs(dfn[mid]); 62 key[now] = (dfn[mid] < 0?-1:1)*key[Abs(dfn[mid])]; 63 if (l < mid) 64 { 65 ch[now][0] = build(l,mid - 1); 66 fa[ch[now][0]] = now; 67 } 68 if (mid < r) 69 { 70 ch[now][1] = build(mid + 1,r); 71 fa[ch[now][1]] = now; 72 } 73 updata(now); return now; 74 } 75 76 inline void init() 77 { 78 int p = (n<<1)+1,q = (n<<1)+2; 79 fa[q] = p; ch[p][1] = q; root = p; 80 ch[q][0] = build(1,n<<1); fa[ch[q][0]] = q; 81 updata(q); updata(p); 82 } 83 84 inline void rotate(int x) 85 { 86 int y = fa[x],z = fa[y],l = ch[y][1] == x,r = l^1; 87 if (z) ch[z][ch[z][1] == y] = x; fa[x] = z; 88 if (ch[x][r]) fa[ch[x][r]] = y; ch[y][l] = ch[x][r]; 89 fa[y] = x; ch[x][r] = y; 90 updata(y); updata(x); 91 } 92 93 inline void splay(int x,int aim) 94 { 95 int top = 0; 96 for (int i = x;i;i = fa[i]) stack[++top] = i; 97 while (top) pushdown(stack[top--]); 98 while (fa[x] != aim) 99 { 100 int y = fa[x],z = fa[y]; 101 if (z != aim) 102 { 103 if ((ch[y][0] == x) ^ (ch[z][0] == y)) rotate(x); 104 else rotate(y); 105 } 106 rotate(x); 107 } 108 if (!aim) root = x; 109 } 110 111 inline int grank(int a) 112 { 113 int ret = size[ch[a][0]] + 1,b = a; 114 for (a = fa[a];a;b = a,a = fa[a]) 115 if (ch[a][1] == b) ret += size[ch[a][0]] + 1; 116 return ret; 117 } 118 119 inline ll calc(int a) 120 { 121 splay((n<<1)+1,0); splay(n+a,(n<<1)+1); 122 return sum[ch[n+a][0]]; 123 } 124 125 inline void add(int a,int b) 126 { 127 int p = find(grank(a)-1),q = find(grank(n+a)+1); 128 splay(p,0); splay(q,p); 129 inc[ch[q][0]] += (ll)b; 130 } 131 132 inline void change(int a,int b) 133 { 134 int p = find(grank(a)-1),q = find(grank(n+a)+1); 135 splay(p,0); splay(q,p); 136 int rt = ch[q][0]; 137 fa[rt] = ch[q][0] = 0; 138 updata(q); updata(p); 139 p = find(grank(n+b)-1); 140 splay(b,0); splay(b+n,b); 141 if (p != b) splay(p,b+n),fa[rt] = p,ch[p][1] = rt,updata(p); 142 else fa[rt] = b+n,ch[b+n][0] = rt; 143 updata(b+n); updata(b); 144 } 145 }tree; 146 147 inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; } 148 149 inline void dfs(int now) 150 { 151 dfn[++cnt] = now; 152 for (int i = side[now];i;i = next[i]) dfs(toit[i]); 153 dfn[++cnt] = -now; 154 } 155 156 int main() 157 { 158 freopen("3786.in","r",stdin); 159 freopen("3786.out","w",stdout); 160 n = read(); 161 for (int i = 2;i <= n;++i) add(read(),i); 162 for (int i = 1;i <= n;++i) tree.key[i] = read(); 163 cnt = 0; dfs(1); 164 tree.init(); m = read(); 165 while (m--) 166 { 167 char opt; 168 do opt = getchar(); while (opt != 'Q'&&opt != 'C' && opt != 'F'); 169 if (opt == 'Q') printf("%lld\n",tree.calc(read())); 170 else if (opt == 'F') { int a = read(),b = read(); tree.add(a,b); } 171 else { int a = read(),b = read(); tree.change(a,b); } 172 } 173 fclose(stdin); fclose(stdout); 174 return 0; 175 }
如果你与我一样一直TLE,也欢迎使用这份代码提交(来自:http://blog.csdn.net/jiangyuze831/article/details/41649235):
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define MAX 600010 6 #define WORKPATH (root->son[1]->son[0]) 7 using namespace std; 8 9 struct SplayTree{ 10 long long val,sum,c,size; 11 long long plus,num,_num; 12 SplayTree *son[2],*father; 13 14 SplayTree(int _,int __); 15 SplayTree() {} 16 bool Check() { 17 return father->son[1] == this; 18 } 19 void Combine(SplayTree *a,bool dir) { 20 son[dir] = a; 21 a->father = this; 22 } 23 void Plus(int c); 24 void PushUp() { 25 sum = son[0]->sum + son[1]->sum + val * (plus ? 1:-1); 26 size = son[0]->size + son[1]->size + 1; 27 num = son[0]->num + son[1]->num + (plus == 1); 28 _num = son[0]->_num + son[1]->_num + (plus == 0); 29 } 30 void PushDown() { 31 if(c) { 32 son[0]->Plus(c); 33 son[1]->Plus(c); 34 c = 0; 35 } 36 } 37 }none,*nil = &none,*root,*tree[MAX]; 38 SplayTree:: SplayTree(int _,int __) { 39 plus = __; 40 if(__ == 1) ++num; 41 if(__ == 0) ++_num; 42 val = _; 43 sum = _ * (plus ? 1:-1); 44 size = 1; 45 c = 0; 46 son[0] = son[1] = nil; 47 } 48 void SplayTree:: Plus(int _) { 49 if(this == nil) return ; 50 sum += _ * (num - _num); 51 val += _; 52 c += _; 53 } 54 55 int points,asks; 56 int head[MAX],total; 57 int next[MAX],aim[MAX]; 58 59 int src[MAX],pos[MAX]; 60 int from[MAX],cnt; 61 int p[MAX]; 62 63 char c[10]; 64 65 inline void Add(int x,int y) 66 { 67 next[++total] = head[x]; 68 aim[total] = y; 69 head[x] = total; 70 } 71 72 void DFS(int x) 73 { 74 pos[++cnt] = src[x]; 75 from[cnt] = x; 76 p[cnt] = true; 77 for(int i = head[x]; i; i = next[i]) 78 DFS(aim[i]); 79 pos[++cnt] = src[x]; 80 from[cnt] = x; 81 p[cnt] = false; 82 } 83 84 void Pretreatment() 85 { 86 nil->son[0] = nil->son[1] = nil->father = nil; 87 nil->val = nil->sum = nil->c = nil->size = 0; 88 p[0] = p[cnt + 1] = -1; 89 } 90 91 SplayTree *BuildTree(int l,int r) 92 { 93 if(l > r) return nil; 94 int mid = (l + r) >> 1; 95 SplayTree *re = new SplayTree(pos[mid],p[mid]); 96 if(p[mid]) tree[from[mid] << 1] = re; 97 else tree[from[mid] << 1|1] = re; 98 re->Combine(BuildTree(l,mid - 1),false); 99 re->Combine(BuildTree(mid + 1,r),true); 100 re->PushUp(); 101 return re; 102 } 103 104 inline void Rotate(SplayTree *a,bool dir) 105 { 106 SplayTree *f = a->father; 107 f->PushDown(),a->PushDown(); 108 f->son[!dir] = a->son[dir]; 109 f->son[!dir]->father = f; 110 a->son[dir] = f; 111 f->father->son[f->Check()] = a; 112 a->father = f->father; 113 f->father = a; 114 f->PushUp(); 115 if(root == f) root = a; 116 } 117 118 inline void Splay(SplayTree *a,SplayTree *aim) 119 { 120 while(a->father != aim) { 121 if(a->father->father == aim) 122 Rotate(a,!a->Check()); 123 else if(!a->father->Check()) { 124 if(!a->Check()) 125 Rotate(a->father,true),Rotate(a,true); 126 else Rotate(a,false),Rotate(a,true); 127 } 128 else { 129 if(a->Check()) 130 Rotate(a->father,false),Rotate(a,false); 131 else Rotate(a,true),Rotate(a,false); 132 } 133 } 134 a->PushUp(); 135 } 136 137 SplayTree *Find(SplayTree *a,int k) 138 { 139 a->PushDown(); 140 if(a->son[0]->size >= k) return Find(a->son[0],k); 141 k -= a->son[0]->size; 142 if(k == 1) return a; 143 return Find(a->son[1],k - 1); 144 } 145 146 inline void SplaySeg(SplayTree *a,SplayTree *b) 147 { 148 int size_1,size_2; 149 Splay(a,nil); 150 size_1 = root->son[0]->size + 1; 151 Splay(b,nil); 152 size_2 = root->son[0]->size + 1; 153 Splay(Find(root,size_1 - 1),nil); 154 Splay(Find(root,size_2 + 1),root); 155 } 156 157 int main() 158 { 159 cin >> points; 160 for(int x,i = 2; i <= points; ++i) { 161 scanf("%d",&x); 162 Add(x,i); 163 } 164 for(int i = 1; i <= points; ++i) 165 scanf("%d",&src[i]); 166 DFS(1); 167 Pretreatment(); 168 root = BuildTree(0,cnt + 1); 169 root->father = nil; 170 cin >> asks; 171 for(int x,y,i = 1; i <= asks; ++i) { 172 scanf("%s",c); 173 if(c[0] == 'Q') { 174 scanf("%d",&x); 175 SplaySeg(tree[1 << 1],tree[x << 1]); 176 printf("%lld\n",WORKPATH->sum); 177 } 178 else if(c[0] == 'C') { 179 scanf("%d%d",&x,&y); 180 SplaySeg(tree[x << 1],tree[x << 1|1]); 181 SplayTree *temp = WORKPATH; 182 WORKPATH = nil; 183 root->son[1]->PushUp(); 184 root->PushUp(); 185 Splay(tree[y << 1],nil); 186 int k = root->son[0]->size + 1; 187 Splay(Find(root,k + 1),root); 188 root->son[1]->Combine(temp,false); 189 root->son[1]->PushUp(); 190 root->PushUp(); 191 } 192 else { 193 scanf("%d%d",&x,&y); 194 SplaySeg(tree[x << 1],tree[x << 1|1]); 195 WORKPATH->Plus(y); 196 } 197 } 198 return 0; 199 }
想要数据的戳这里。(里面的std可能有误,我交了一发果断RE)