bzoj3786星系探索 splay
3786: 星系探索
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 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
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.保证操作合法。注意w_i>=0
Source
很好的一个题目,让我对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 }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。