BZOJ3786星系探索——非旋转treap(平衡树动态维护dfs序)
题目描述
物理学家小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可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。
输入
第一行一个整数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.
输出
对于每一个事件类型为Q的事件,输出一行一个整数,表示此次实验的收集器最终能量。
样例输入
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2
样例输出
15
25
提示
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。注意w_i>=0
如果没有迁移子树操作考虑怎么做?
求出原树出栈入栈序(下文用dfs序代替),对于入栈点权值为正(即val[x]),对于出站点权值为负(即-val[x]),那么询问就是求询问点在dfs序上入栈点的前缀和(不在这个点到根路径上的点出栈点和入栈点一定同时在询问点的前边,正负权值抵消)。
对于修改一定是dfs序上的一段区间,用线段树区间修改即可,因为每个点可能是正权可能是负权,因此还要维护区间正权点数与负权点数之差。
那么现在有了子树迁移操作,dfs序是动态的了,显然线段树无法实现,那么用平衡树就好了。
将操作点子树从treap中分裂出来然后插入到它新的父节点入栈点后面即可。
但因为这道题我们只知道dfs序上每个点对应平衡树上节点的编号(建树时开两个数组分别存一下),所以要再维护出平衡树上每个点的父节点然后每次分裂前先从操作点往上找到根节点来得到这个点在平衡树上的具体位置(即它现在是dfs序的第几个点)再从根正常分裂。
这道题严重卡常,建议用上所有优化,蒟蒻的我差点没卡过去QAQ。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
__attribute__((optimize("-O3")))int rd() {
register int x=0;register char ch=nc();
while(ch<'0'||ch>'9') ch=nc();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=nc();
return x;
}
int n,m;
int x,y;
int tot;
int cnt;
int res;
int root;
int a,b,c;
int head[200010];
int to[200010];
int next[200010];
int num[200010];
int sig[200010];
ll sum[200010];
int v[200010];
int val[200010];
int pos[200010];
int size[200010];
int ls[200010];
int rs[200010];
int f[200010];
int r[200010];
int s[200010];
int t[200010];
int p[200010];
int q[200010];
inline void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
inline int build(int val,int k)
{
int rt=++cnt;
r[rt]=rand();
size[rt]=1;
v[rt]=val*k;
sum[rt]=1ll*v[rt];
sig[rt]=k;
num[rt]=sig[rt];
return rt;
}
inline void pushup(int rt)
{
size[rt]=size[ls[rt]]+size[rs[rt]]+1;
num[rt]=sig[rt];
sum[rt]=1ll*v[rt];
if(ls[rt])
{
num[rt]+=num[ls[rt]];
sum[rt]+=sum[ls[rt]];
}
if(rs[rt])
{
num[rt]+=num[rs[rt]];
sum[rt]+=sum[rs[rt]];
}
}
inline void pushdown(int rt)
{
if(pos[rt])
{
pos[ls[rt]]+=pos[rt];
pos[rs[rt]]+=pos[rt];
sum[ls[rt]]+=1ll*num[ls[rt]]*pos[rt];
sum[rs[rt]]+=1ll*num[rs[rt]]*pos[rt];
v[ls[rt]]+=sig[ls[rt]]*pos[rt];
v[rs[rt]]+=sig[rs[rt]]*pos[rt];
pos[rt]=0;
}
}
inline int merge(int x,int y)
{
pushdown(x);
pushdown(y);
if(!x||!y)
{
return x+y;
}
if(r[x]<r[y])
{
rs[x]=merge(rs[x],y);
if(rs[x])
{
f[rs[x]]=x;
}
pushup(x);
return x;
}
else
{
ls[y]=merge(x,ls[y]);
if(ls[y])
{
f[ls[y]]=y;
}
pushup(y);
return y;
}
}
inline void split(int rt,int &x,int &y,int k)
{
pushdown(rt);
if(!rt)
{
x=y=0;
return ;
}
if(size[ls[rt]]>=k)
{
y=rt;
split(ls[rt],x,ls[y],k);
if(ls[y])
{
f[ls[y]]=y;
}
pushup(rt);
}
else
{
x=rt;
split(rs[rt],rs[x],y,k-size[ls[rt]]-1);
if(rs[x])
{
f[rs[x]]=x;
}
pushup(rt);
}
}
inline int get_size(int rt)
{
int ans=0;
int flag=1;
while(rt)
{
if(flag)
{
ans+=size[ls[rt]]+1;
}
flag=(rt==rs[f[rt]]);
rt=f[rt];
}
return ans;
}
inline void dfs(int x)
{
s[x]=build(val[x],1);
root=merge(root,s[x]);
for(int i=head[x];i;i=next[i])
{
dfs(to[i]);
}
t[x]=build(val[x],-1);
root=merge(root,t[x]);
}
int main()
{
srand(12378);
n=rd();
for(int i=2;i<=n;i++)
{
x=rd();
add(x,i);
}
for(int i=1;i<=n;i++)
{
val[i]=rd();
}
dfs(1);
m=rd();
while(m--)
{
char op=nc();
while(op!='C'&&op!='Q'&&op!='F')op=nc();
int x=rd();
if(op=='Q')
{
res=get_size(s[x]);
split(root,a,b,res);
f[a]=f[b]=0;
printf("%lld\n",sum[a]);
root=merge(a,b);
}
else if(op=='F')
{
y=rd();
res=get_size(t[x]);
split(root,b,c,res);
f[b]=f[c]=0;
res=get_size(s[x]);
split(b,a,b,res-1);
f[a]=f[b]=0;
pos[b]+=y;
sum[b]+=1ll*num[b]*y;
v[b]+=sig[b]*y;
root=merge(merge(a,b),c);
}
else
{
y=rd();
res=get_size(t[x]);
split(root,b,c,res);
f[b]=f[c]=0;
res=get_size(s[x]);
split(b,a,b,res-1);
f[a]=f[b]=0;
root=merge(a,c);
res=get_size(s[y]);
split(root,a,c,res);
f[a]=f[c]=0;
root=merge(merge(a,b),c);
}
}
}
BZOJ3786星系探索——非旋转treap(平衡树动态维护dfs序)的更多相关文章
- BZOJ3159决战——树链剖分+非旋转treap(平衡树动态维护dfs序)
题目描述 输入 第一行有三个整数N.M和R,分别表示树的节点数.指令和询问总数,以及X国的据点. 接下来N-1行,每行两个整数X和Y,表示Katharon国的一条道路. 接下来M行,每行描述一个指令或 ...
- BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...
- BZOJ2690: 字符串游戏(平衡树动态维护Dfs序)
Description 给定N个仅有a~z组成的字符串ai,每个字符串都有一个权值vi,有M次操作,操作分三种: Cv x v':把第x个字符串的权值修改为v' Cs x a':把第x个字符串修改成a ...
- 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)
在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树
直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势: AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区 ...
随机推荐
- Oracle ORA-01940: 无法删除当前连接的用户
当我们要删除一个oracle的用户时,如果有其他人连接到数据库则会报以下错误: ORA-01940: 无法删除当前连接的用户 处理办法就是:将连接到当前用户的session给kill掉. 处理步骤如下 ...
- [01] JSP的基本认识
1.什么是JSP JSP,全称JavaServer Pages,是由Sun Microsystems公司倡导和许多公司参与共同建立的一种使软件开发者可以响应客户端请求,而动态生成HTML.XML或其他 ...
- c语言学习5
break 和 continue之间的区别: 在1000人中,募捐100000元,当达到10万元后结束 break 跳出当前循环,即 是终止循环,continue结束本次循环,不终止循环 #in ...
- 微软下一代Web前端技术Blazor(C#编译为WebAssembly)
W3C Web标准化机构在制定下一代的网页技术WebAssembly.目前版本是1.0,主流浏览器的最新版本都已经支持.其特点是浏览器可以执行编译后的二进制程序,不需要像之前的程序,浏览器下载Java ...
- xhtml和html的区别 html5和xhtml的区别
xhtml和html的区别 - 分为两大类比较:一个是功能上的差别,另外是书写习惯的差别.关于功能上的差别,主要是XHTML可兼容各大浏览器.手机以及PDA,并且浏览器也能快速正确地编译网页,- XH ...
- 安卓自动化测试案例(跑在MonkeyRunner上)
首先文件所在目录: MonkeyRunner所在目录: 运行命令(通过cd 命令 进入Tools目录下): 运行脚本:monkeyrunner.bat ..\honeywell\jsq.py 源文件 ...
- HDU 1109 Run Away
题目大意:给一个矩阵的长宽,再给n个点,求矩阵区域内某个点到各个点的最小距离的最大值,输出所求点的坐标 这道题我还是写了随机化乱搞,不过由于比较懒于是就没有写模拟退火,不过也是可以AC的 我们先初始随 ...
- 51Nod 1443 路径和树
还是一道很简单的基础题,就是一个最短路径树的类型题目 我们首先可以发现这棵树必定满足从1出发到其它点的距离都是原图中的最短路 换句话说,这棵树上的每一条边都是原图从1出发到其它点的最短路上的边 那么直 ...
- 使用xshell连接服务器,数字键盘无法使用解决办法
打开会话管理器,选中需要设置的服务器连接,右键->属性 选中 终端->VT模式->初始数字键盘模式->设为普通 保存,重新连接即可.
- 实例解析forEach、for...in与for...of
在开发过程中经常需要循环遍历数组或者对象,js也为我们提供了不少方法供使用,其中就有三兄弟forEach.for...in.for...of,这三个方法应该是使用频率最高的,但很多人却一值傻傻分不清, ...