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

    3
    1
    1
    4 5 7
    5
    Q 2
    F 1 3
    Q 2
    C 2 3
    Q 2

    Sample Output

    9
    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
    ",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 }
  • 相关阅读:
    Python类知识点
    安装psycopg2时出错:Error: pg_config executable not found.
    top命令
    Ubuntu18.10创建软件图标
    初始化Redis密码
    Ubuntu修改root密码,ssh 允许root用户登录
    Flask_Migrate数据库迁移
    Ubuntu18.04 systemd开机自启
    dnspython
    记一次Celery的仇
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/9600948.html
Copyright © 2011-2022 走看看