zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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)

  • 相关阅读:
    JS之事件及冒泡
    DOM读取和修改内联样式
    dom查询与修改的一些常用方法
    js修改this指向的三种方法(call,bind,apply)
    JS原型概念
    JS创建对象
    JS的this(谁调用就指向谁)
    变量声明提前与函数声明提前
    JS对象创建
    正则应用之数据采集房屋网站信息
  • 原文地址:https://www.cnblogs.com/mmlz/p/4297657.html
Copyright © 2011-2022 走看看