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

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.保证操作合法。

 

不得不说这是一道好题,但同时也是一道鬼题。(TMD本机上 27s BZOJ上 TLE ,什么鬼!!!)
dfs序这东西又冒出来了,还升级了,呵呵。。。。这次的dfs序好像叫什么进栈出栈序(好像也叫欧拉序列)吧。
肯定会有许多人想要问dfs序不是只能处理子树信息,不能处理链信息吗?这边是本题最妙的地方——利用欧拉序列,每个点u进栈dfs序所对应的权值为正,出栈dfs序所对应的权值为负(绝对值都是该点u的权值)。设根为root,该点为a点,其入栈序为t1,出栈序为t2。那么树上a到root的权值和就是dfs序在1到t2-1的所对应的权值和。
证明根据欧拉序列的性质想一想应该就可以明白了(不在a到root这条链上的权值都通过一正一负抵消了)。
换父亲操作也很容易,假设将a的父亲换为b,令a的进栈出栈序分别为ta1和ta2,b的为tb1和tb2。我们只需要把ta1到ta2这段区间整体地移动到tb1后或者tb2前即可(必须要挨着tb1或tb2)。
用splay随便搞搞就可以了。
 
我的代码(可对拍,交bzoj TLE,本机O2 26s):
  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 }
View Code

 

如果你与我一样一直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 }
View Code

 

想要数据的戳这里。(里面的std可能有误,我交了一发果断RE)

高考结束,重新回归。
posted @ 2015-02-22 19:56  lmxyy  阅读(175)  评论(0编辑  收藏  举报