bzoj3786星系探索 splay

3786: 星系探索

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 1314  Solved: 425
[Submit][Status][Discuss]

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.保证操作合法。注意w_i>=0

Source

By 佚名上传

很好的一个题目,让我对splay的理解加深了很多
求路径的和,首先应该想到树转序列
但如果用链剖+线段树,是无法修改父子关系的
看了看题解,说的是splay+dfs序,感觉美妙
可以记录一颗子树的入点和出点,这样就把一颗子树转化成了一段区间,如果修改父子关系,整体把某颗子树区间移动到一个节点后面
如果要求树上点到根的权值和,可以选择差分,入点+ 出点-
维护子树需要维护子树中有多少入点和出点
一颗子树整体加上某个值时,标记区间,区间的根节点 +val*(入点数-出点数)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define F(i,a,b) for(int i=a;i<=b;i++)
  6 #define ll long long
  7 #define maxn 200100
  8 using namespace std;
  9 int n,q,rt,top,cnt,tot;
 10 int a[maxn],sta[maxn],head[maxn],fa[maxn],w[maxn],v[maxn],tag[maxn];
 11 int c[maxn][2],t[maxn][2],s[maxn][2];
 12 ll sum[maxn];
 13 struct edge_type
 14 {
 15     int next,to;
 16 }e[maxn];
 17 inline int read()
 18 {
 19     int x=0,f=1;char ch=getchar();
 20     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
 21     while (ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 22     return x*f;
 23 }
 24 inline void add_edge(int x,int y)
 25 {
 26     e[++cnt]=(edge_type){head[x],y};head[x]=cnt;
 27 }
 28 inline void dfs(int x)
 29 {
 30     v[t[x][0]=++tot]=a[x];w[tot]=1;
 31     for(int i=head[x];i;i=e[i].next) if (!t[e[i].to][0]) dfs(e[i].to);
 32     v[t[x][1]=++tot]=-a[x];w[tot]=-1;
 33 }
 34 inline void pushup(int x)
 35 {
 36     if (!x) return;
 37     int l=c[x][0],r=c[x][1];
 38     s[x][0]=s[l][0]+s[r][0]+(w[x]==1);
 39     s[x][1]=s[l][1]+s[r][1]+(w[x]==-1);
 40     sum[x]=sum[l]+sum[r]+(ll)v[x];
 41 }
 42 inline void update(int x,ll z)
 43 {
 44     if (!x) return;
 45     sum[x]+=(ll)(s[x][0]-s[x][1])*z;
 46     v[x]+=w[x]*z;
 47     tag[x]+=z;
 48 }
 49 inline void pushdown(int x)
 50 {
 51     if (!x) return;
 52     if (!tag[x]) return;
 53     update(c[x][0],tag[x]);
 54     update(c[x][1],tag[x]);
 55     tag[x]=0;
 56 }
 57 inline void rotate(int x,int &k)
 58 {
 59     int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
 60     if (y!=k) c[z][c[z][1]==y]=x;else k=x;
 61     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
 62     c[y][l]=c[x][r];c[x][r]=y;
 63     pushup(y);pushup(x);
 64 }
 65 inline void splay(int x,int &k)
 66 {
 67     for(int i=x;i;i=fa[i]) sta[++top]=i;
 68     while (top) pushdown(sta[top--]);
 69     while (x!=k)
 70     {
 71         int y=fa[x],z=fa[y];
 72         if (y!=k)
 73         {
 74             if ((c[z][0]==y)^(c[y][0]==x)) rotate(x,k);
 75             else rotate(y,k);
 76         }
 77         rotate(x,k);
 78     }
 79 }
 80 inline int findmin(int x)
 81 {
 82     while (c[x][0]) x=c[x][0];
 83     return x;
 84 }
 85 inline int findmax(int x)
 86 {
 87     while (c[x][1]) x=c[x][1];
 88     return x;
 89 }
 90 inline void split(int x,int y)
 91 {
 92     splay(x,rt);
 93     int t1=findmax(c[x][0]);
 94     splay(y,rt);
 95     int t2=findmin(c[y][1]);
 96     splay(t1,rt);
 97     splay(t2,c[t1][1]);
 98 }
 99 inline void build(int l,int r,int f)
100 {
101     if (l>r) return;
102     int x=(l+r)>>1;
103     fa[x]=f;c[f][x>f]=x;
104     if (l==r){sum[x]=v[x];s[x][0]=w[x]==1;s[x][1]=1-s[x][0];return;}
105     build(l,x-1,x);build(x+1,r,x);
106     pushup(x);
107 }
108 int main()
109 {
110     n=read();
111     F(i,2,n){int x=read();add_edge(x,i);}
112     F(i,1,n) a[i]=read();
113     tot=1;dfs(1);
114     build(1,2*n+2,0);
115     rt=n+1;
116     q=read();
117     while (q--)
118     {
119         char ch=getchar();
120         while (ch<‘A‘||ch>‘Z‘) ch=getchar();
121         if (ch==‘Q‘)
122         {
123             int x=read();
124             splay(t[1][0],rt);splay(t[x][0],c[rt][1]);
125             printf("%lld\n",sum[c[c[rt][1]][0]]+(ll)v[rt]+(ll)v[c[rt][1]]);
126         }
127         else if (ch==‘F‘)
128         {
129             int x=read(),y=read(),z;
130             splay(t[x][0],rt);splay(t[x][1],c[rt][1]);
131             z=c[rt][1];
132             v[rt]+=w[rt]*y;v[z]+=w[z]*y;
133             update(c[z][0],y);
134             pushup(z);pushup(rt);
135         }
136         else
137         {
138             int x=read(),y=read(),z,tmp;
139             split(t[x][0],t[x][1]);
140             z=c[rt][1];tmp=c[z][0];c[z][0]=0;
141             pushup(z);pushup(rt);
142             splay(t[y][0],rt);
143             splay(findmin(c[rt][1]),c[rt][1]);
144             z=c[rt][1];c[z][0]=tmp;fa[tmp]=z;
145             pushup(z);pushup(rt);
146         }
147     }
148     return 0;
149 }  
时间: 2024-08-28 07:40:05

bzoj3786星系探索 splay的相关文章

Bzoj3786: 星系探索——Splay

题面  Bzoj3786 解析  上课讲稿上的例题 这道题是套路题,是括号序的应用,进入节点时打上$+1$标记, 退出时打上$-1$标记,这个是作为点权的系数 先看操作2, 需要更改父节点,就是把一段区间提取出来,插入另一个地方,显然可以用Splay维护,先提取区间,再把新父亲的$+1$点旋转至根,把区间挂在根的后继的左儿子上,再把这个节点旋转至根,以更新信息 对于操作1,求点到根的路径和,就是求括号序列的前缀和,该点对应的$+1$点或$-1$点的前缀和都可,我是把$-1$的点旋转至根,答案就是

【BZOJ-3786】星系探索 Splay + DFS序

3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 647  Solved: 212[Submit][Status][Discuss] Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系

[BZOJ3786]星系探索(伪ETT)

3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1638  Solved: 506[Submit][Status][Discuss] Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关

[BZOJ 3786] 星系探索 Splay维护入栈出栈序

题意 给定一棵 n 个节点, 点有点权, 以 1 为根的有根树. m 次操作: ① 查询点 d 到根的点权之和. ② 将 x 及其子树截出来, 作为 y 的儿子. ③ 将以 p 为根的子树的点权增加 q . $n \le 100000$ . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <vector>

Bzoj3786 星系探索

Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1036  Solved: 342 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球

BZOJ 3786 星系探索 Splay维护树的入栈出栈序

题目大意:给出一棵树,要求有以下这些操作:1.求出一个节点到根的点权和.2.将一个节点的父亲改变.3.将一个子树中的每一个节点都加上一个权值. 思路:LCT就不用想了,因为有子树操作.然后就是一个很神奇的东西了,就是Splay维护树的入栈出栈序.这个玩应是做了这个题之后才知道的.但是感觉真的很dio. 首先,我们先按照题意,将树建出来.然后从根开始深搜,这样一个点进入DFS函数和出DFS函数的时候就会有两个时间点,就是入栈的时间和出栈的时间.然后利用Splay维护一个序列,就是入栈出栈的顺序.在

bzoj 3786 星系探索 (splay+dfs序)

题目大意:给你一棵树,支持一下三种操作 1.获取某节点到根节点的路径上所有节点的权值和 2.更换某棵子树的父亲 3.某子树内所有节点的权值都增加一个值w 当时想到了splay维护dfs序,查完题解发现思路是对的,然后我就写了足足6个小时才A st[x]代表入栈时间,ed[x]代表出栈时间 对于第一个操作,每个树上节点在splay中都有两个位置,分别对应入栈出栈序,然后把入栈的点权*1,出栈点权*-1,就可以避免其它子树干扰了 接着查询到根节点的路径权值和呢,splay把1~st[x]整个序列都扔

BZOJ3786 星系探索 蒟蒻出题人给跪

本蒟蒻闲得蛋疼于是在BZOJ上加了一道水题,果然被瞬间水过... 只能说本蒟蒻实在是太弱了. Q:你为什么要写这篇博客? A:我只是为了水经验233.... 正常向的数据.题解.标程请自行传送下面的云盘... http://pan.baidu.com/s/1qWsMHM8 吐槽: 为什么本地不开O2 10s在OJ上开O2 还需要20+s啊!!!我本来不想卡常数好不好. 因为这个原因用数组实现数据结构被卡的请见谅...现在是40s应该卡不掉了. 另外如果发现自己被卡掉请重交一次.原因不解释. 为什

bzoj3786 星际探索 splay dfs序

这道题 首先 因为他求的是当前点到根节点的路径和 我们可以将题目转换为括号序列的写法 将点拆为左括号以及右括号 左括号为正 右括号为负 这样题目就变为了求前缀和了 如果一个点是这个点的子树 那么他的左右括号就一定包含在所求区间里 会被抵消掉而不影响结果. 这样我们可以利用dfs序建树 操作为区间加 单点修改 树的合并以及分裂 一起区间和 当然区间加因为我们维护的是括号序列 所以区间加的时候我们就要将左括号加w而右括号减w 但是我们因此我们还要记录这个点子树及其本身的左右括号差 区间加就加上左括号