3786: 星系探索

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 647  Solved: 212
[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.保证操作合法。

Source

By 佚名上传

Solution

子树有关修改,显然不能用Link-Cut-Tree...

考虑用DFS序,但换根操作显然不能用线段树维护,所以用支持分裂合并的Splay!
我们把DFS序中的入栈出栈分开,在一个点入栈时权值为+val[x],出栈时权值为-val[x],这样对于他的子树,影响显然会抵消

这样的话,查询点x到跟的$\sum_{x}^{root}val[x]$,就相当于前缀和查询$\sum_{pl[1]}^{pl[x]}val[x]$

子树修改,就是打标记。

换根操作,把x换到y,先把x的子树区间分裂开,再把y的子树区间提取,然后把x的子树区间连到y的子树区间最左即可

Code

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<stack>
  7. using namespace std;
  8. inline int read()
  9. {
  10. int x=; char ch=getchar();
  11. while (ch<'' || ch>'') {ch=getchar();}
  12. while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
  13. return x;
  14. }
  15. #define LL long long
  16. #define MAXN 200010
  17. int N,M,power[MAXN],val[MAXN];
  18. struct EdgeNode{int next,to,d;}edge[MAXN<<];
  19. int head[MAXN],cnt=;
  20. inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
  21. inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
  22. int pl[MAXN],dfn,pr[MAXN],pre[MAXN],del[MAXN];
  23. void DFS(int now,int last)
  24. {
  25. pl[now]=++dfn; pre[dfn]=now; del[dfn]=;
  26. for (int i=head[now]; i; i=edge[i].next)
  27. if (edge[i].to!=last)
  28. DFS(edge[i].to,now);
  29. pr[now]=++dfn; del[dfn]=-;
  30. }
  31. namespace SplayTree
  32. {
  33.  
  34. int fa[MAXN],son[MAXN][],sz,root,ln[MAXN],rn[MAXN],pos[MAXN];
  35. LL sum[MAXN],tag[MAXN];
  36. //ln记录左的数量,rn记录右的数量,tag标记
  37. #define ls(x) son[x][0]
  38. #define rs(x) son[x][1]
  39. #define INF 1000100
  40.  
  41. inline void Update(int now)
  42. {
  43. sum[now]=sum[ls(now)]+sum[rs(now)]+(LL)val[now];
  44. ln[now]=ln[ls(now)]+ln[rs(now)]+(del[now]==);
  45. rn[now]=rn[ls(now)]+rn[rs(now)]+(del[now]==-);
  46. }
  47. inline void paint(int now,LL D) {if (now) val[now]+=D*del[now],sum[now]+=D*(ln[now]-rn[now]),tag[now]+=D;}
  48. inline void PushDown(int now)
  49. {
  50. if (!tag[now]) return;
  51. LL D=tag[now]; tag[now]=;
  52. if (ls(now)) paint(ls(now),D);
  53. if (rs(now)) paint(rs(now),D);
  54. }
  55. void print(int now)
  56. {
  57. PushDown(now);
  58. if (val[now]!=INF && val[now]!=-INF)
  59. printf("ID=%d ---%d [%d %d] %d %I64d %d %d %d %I64d\n",
  60. now,fa[now],ls(now),rs(now),val[now],sum[now],ln[now],rn[now],del[now],tag[now]);
  61. if (son[now][]) print(son[now][]);
  62. if (son[now][]) print(son[now][]);
  63. }
  64. inline bool Right(int now) {return son[fa[now]][]==now;}
  65. inline void rotate(int now)
  66. {
  67. PushDown(fa[now]); PushDown(now);
  68. int f=fa[now],gf=fa[f],wh=Right(now);
  69. son[f][wh]=son[now][wh^]; fa[son[f][wh]]=f;
  70. fa[f]=now; son[now][wh^]=f; fa[now]=gf;
  71. if (gf) son[gf][son[gf][]==f]=now;
  72. Update(f); Update(now);
  73. }
  74. inline void splay(int now,int tar)
  75. {
  76. for (int f; (f=fa[now])!=tar; rotate(now))
  77. if (fa[f]!=tar) rotate(Right(now)==Right(f)? f:now);
  78. if (!tar) root=now;
  79. }
  80. inline int fmin(int x) {while (son[x][]) x=son[x][]; return x;}
  81. inline int fmax(int x) {while (son[x][]) x=son[x][]; return x;}
  82. inline void Split(int l,int r)
  83. {
  84. splay(l,); int x=fmax(ls(root));
  85. splay(r,); int y=fmin(rs(root));
  86. splay(x,); splay(y,x);
  87. }
  88. inline LL Query(int pos) {Split(pl[],pl[pos]); return sum[ls(rs(root))];}
  89. inline void Change(int x,int D)
  90. {
  91. Split(pl[x],pr[x]);
  92. int rt=son[rs(root)][];
  93. sum[rt]+=(LL)(ln[rt]-rn[rt])*D; val[rt]+=D*del[rt]; tag[rt]+=D;
  94. Update(rs(root)); Update(root);
  95. }
  96. inline void BuildTree(int l,int r,int last)
  97. {
  98. if (r<l) return;
  99. int mid=(l+r)>>,now=mid;
  100. fa[now]=last; son[last][now>last]=now;
  101. if (l==r)
  102. {sum[now]=val[now]; ln[now]=del[now]==; rn[now]=-ln[now]; return;}
  103. BuildTree(l,mid-,now); BuildTree(mid+,r,now);
  104. Update(now);
  105. }
  106. inline void Init() {BuildTree(,(N<<)+,); root=(+(N<<)+)>>;}
  107. inline void MakeRoot(int now,int father)
  108. {
  109. Split(pl[now],pr[now]);
  110. int rt=ls(rs(root));
  111. fa[ls(rs(root))]=;
  112. son[rs(root)][]=;
  113. Update(rs(root)),Update(root);
  114. splay(pl[father],); splay(fmin(rs(root)),root);
  115. son[rs(root)][]=rt; fa[rt]=rs(root);
  116. Update(rs(root)),Update(root);
  117. }
  118. }
  119. using namespace SplayTree;
  120. int main()
  121. {
  122. N=read();
  123. for (int i=; i<=N; i++) InsertEdge(i,read());
  124. dfn=; DFS(,);
  125. for (int i=; i<=N; i++) power[i]=read();
  126. // for (int i=1; i<=N; i++) printf("id=%d [%d , %d]\n",pre[i],pl[pre[i]],pr[pre[i]]);
  127. for (int i=; i<=N; i++) val[pl[i]]+=power[i],val[pr[i]]-=power[i];
  128. // for (int i=1; i<=dfn; i++) printf("%d ",val[i]); puts("");
  129. M=read();
  130. SplayTree::Init();
  131. while (M--)
  132. {
  133. // print(root);
  134. char opt[]; scanf("%s",opt); int x,y;
  135. if (opt[]=='Q') x=read(),printf("%I64d\n",SplayTree::Query(x));
  136. if (opt[]=='C') x=read(),y=read(),SplayTree::MakeRoot(x,y);
  137. if (opt[]=='F') x=read(),y=read(),SplayTree::Change(x,y);
  138. }
  139. return ;
  140. }

一天前..我:char哥,要是DFS序不用线段树,用Splay的话,不就可以支持子树交换XXX了吗...    char哥:...woc!这么科学....

于是跟char哥连坐,写了一天Splay,然后这道题昨天没调出来...

终于写出来了...40s时限41s  AC....

我:我一定要压到40s以内!    .....  我:当我没说;

我:char哥,你有什么压常数的技巧么?   char哥:重写,你这程序已经没救了!......

本机加O2优化:

【BZOJ-3786】星系探索 Splay + DFS序的更多相关文章

  1. BZOJ 3786 星系探索 (splay+dfs序)

    题目大意:给你一棵树,支持一下三种操作 1.获取某节点到根节点的路径上所有节点的权值和 2.更换某棵子树的父亲 3.某子树内所有节点的权值都增加一个值w 当时想到了splay维护dfs序,查完题解发现 ...

  2. BZOJ3786: 星系探索 Splay+DFS序

    题目大意:给你一个树,支持三种操作,子树加,点到根的路径和,改变某一个点的父亲. 分析: 看起来像一个大LCT,但是很显然,LCT做子树加我不太会啊... 那么,考虑更换一个点的父亲这个操作很有意思, ...

  3. BZOJ 3786 星系探索 ——Splay

    子树可以移动,唔. 还是用Splay维护DFS序即可. 子树的话直接截取出来就好了. 然后求前驱后继可能麻烦一些. 添加两个虚拟节点会比较好写. #include <map> #inclu ...

  4. bzoj 3786 星系探索 dfs+splay

    [BZOJ3786]星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球 ...

  5. BZOJ 3786: 星系探索 解题报告

    3786: 星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅 ...

  6. BZOJ 3786 星系探索

    Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球 ...

  7. bzoj3786 星际探索 splay dfs序

    这道题 首先 因为他求的是当前点到根节点的路径和 我们可以将题目转换为括号序列的写法 将点拆为左括号以及右括号 左括号为正 右括号为负 这样题目就变为了求前缀和了 如果一个点是这个点的子树 那么他的左 ...

  8. BZOJ3786:星系探索(Splay,括号序)

    Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球 ...

  9. BZOJ 3786: 星系探索 欧拉游览树

    一个叫 Euler-Tour-Tree 的数据结构,说白了就是用 Splay_Tree 维护欧拉序 #include <cstring> #include <algorithm> ...

随机推荐

  1. Frequently Asked Questions - P-thresholds

    Source: http://mindhive.mit.edu/book/export/html 1. What is the multiple-comparison problem? What is ...

  2. python处理经过gzip压缩的网页内容

    Python在进行网页抓取时,有时会获取到经过gzip压缩后的数据(体积小,传输快),导致无法阅读和使用. 如图所示,为http原始报文.可以看到,header区域的“Content-Encoding ...

  3. AngularJS中的事件

    欢迎大家指导与讨论 : ) 前言  Angular的作用域在本质上是分层次的(有的住户在低层, 有的住户在高层), 它们可以通过父子关系很自然地进行沟通.但通常, 这种沟通是单向的(父->子的单 ...

  4. UIScrollView增加刷新

    1. if (!self.scrollView) { CGRect frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), CGRe ...

  5. codevs 3165 爱改名的小融2

    3149 爱改名的小融 2 http://codevs.cn/problem/3149/ 题目描述 Description Wikioi上有个人叫小融,他喜欢改名.现在他的要求变了,只要是英文字母就是 ...

  6. SQL基础之GROUPING

    1.grouping sets 记得前几天第一次接触grouping sets时,笔者的感觉是一脸懵逼. 后来一不小心看到msdn上对grouping sets的说明,顿时豁然开朗,其实groupin ...

  7. SQLServer(MSSQL)、MySQL、SQLite、Access相互迁移转换工具 DB2DB v1.0

    最近公司有一个项目,需要把原来的系统从 MSSQL 升迁到阿里云RDS(MySQL)上面.为便于测试,所以需要把原来系统的所有数据表以及测试数据转换到 MySQL 上面.在百度上找了很多方法,有通过微 ...

  8. [poj 3537]Crosses and Crosses(博弈论)

    题目:http://poj.org/problem?id=3537 题意:给你n个格子,两个人依次在n个格子的任意空位置画"X",谁如果画了一个后,3个X连在了一起,那么那个人就获 ...

  9. SqlServer——批量插入数据

    像Major表里面批量插入数据演示: 代码如下: Declare @I int Set @I= Begin Tran InsertData: Insert into Major values(@I,' ...

  10. webpack入坑之旅(五)加载vue单文件组件

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...