bzoj3786 星际探索

11 篇文章 0 订阅
8 篇文章 0 订阅

3786: 星系探索

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 394   Solved: 133
[ 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




首先我们用DFS序记录每个点进入和退出的时间,这样就将树上的操作转变为区间操作。

我们假设进入的时候权值为正,退出的时候权值为负,那么每个点到根节点的权值和就等于前缀和。

然后问题转化为区间修改、区间查询、区间移动,用splay来解决。之后就是各种各样splay的操作了。。。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 200100
#define inf 1000000000
using namespace std;
int n,q,rt,top,cnt,tot;
int a[maxn],sta[maxn],head[maxn],fa[maxn],w[maxn],v[maxn],tag[maxn];
int c[maxn][2],t[maxn][2],s[maxn][2];
ll sum[maxn];
struct edge_type
{
	int next,to;
}e[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y)
{
	e[++cnt]=(edge_type){head[x],y};head[x]=cnt;
}
inline void dfs(int x)
{
	v[t[x][0]=++tot]=a[x];w[tot]=1;
	for(int i=head[x];i;i=e[i].next) if (!t[e[i].to][0]) dfs(e[i].to);
	v[t[x][1]=++tot]=-a[x];w[tot]=-1;
}
inline void pushup(int x)
{
	if (!x) return;
	int l=c[x][0],r=c[x][1];
	s[x][0]=s[l][0]+s[r][0]+(w[x]==1);
	s[x][1]=s[l][1]+s[r][1]+(w[x]==-1);
	sum[x]=sum[l]+sum[r]+(ll)v[x];
}
inline void update(int x,ll z)
{
	if (!x) return;
	sum[x]+=(ll)(s[x][0]-s[x][1])*z;
	v[x]+=w[x]*z;
	tag[x]+=z;
}
inline void pushdown(int x)
{
	if (!x) return;
	if (!tag[x]) return;
	update(c[x][0],tag[x]);
	update(c[x][1],tag[x]);
	tag[x]=0;
}
inline void rotate(int x,int &k)
{
	int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
	if (y!=k) c[z][c[z][1]==y]=x;else k=x;
	fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
	c[y][l]=c[x][r];c[x][r]=y;
	pushup(y);pushup(x);
}
inline void splay(int x,int &k)
{
	for(int i=x;i;i=fa[i]) sta[++top]=i;
	while (top) pushdown(sta[top--]);
	while (x!=k)
	{
		int y=fa[x],z=fa[y];
		if (y!=k)
		{
			if (c[z][0]==y^c[y][0]==x) rotate(x,k);
			else rotate(y,k);
		}
		rotate(x,k);
	}
}
inline int findmin(int x)
{
	while (c[x][0]) x=c[x][0];
	return x;
}
inline int findmax(int x)
{
	while (c[x][1]) x=c[x][1];
	return x;
}
inline void split(int x,int y)
{
	splay(x,rt);
	int t1=findmax(c[x][0]);
	splay(y,rt);
	int t2=findmin(c[y][1]);
	splay(t1,rt);
	splay(t2,c[t1][1]);
}
inline void build(int l,int r,int f)
{
	if (l>r) return;
	int x=(l+r)>>1;
	fa[x]=f;c[f][x>f]=x;
	if (l==r){sum[x]=v[x];s[x][0]=w[x]==1;s[x][1]=1-s[x][0];return;}
	build(l,x-1,x);build(x+1,r,x);
	pushup(x);
}
int main()
{
	n=read();
	F(i,2,n){int x=read();add_edge(x,i);}
	F(i,1,n) a[i]=read();
	tot=1;dfs(1);
	build(1,2*n+2,0);
	rt=n+1;
	q=read();
	while (q--)
	{
		char ch=getchar();
		while (ch<'A'||ch>'Z') ch=getchar();
		if (ch=='Q')
		{
			int x=read();
			splay(t[1][0],rt);splay(t[x][0],c[rt][1]);
			printf("%lld\n",sum[c[c[rt][1]][0]]+(ll)v[rt]+(ll)v[c[rt][1]]);
		}
		else if (ch=='F')
		{
			int x=read(),y=read(),z;
			splay(t[x][0],rt);splay(t[x][1],c[rt][1]);
			z=c[rt][1];
			v[rt]+=w[rt]*y;v[z]+=w[z]*y;
			update(c[z][0],y);
			pushup(z);pushup(rt);
		}
		else
		{
			int x=read(),y=read(),z,tmp;
			split(t[x][0],t[x][1]);
			z=c[rt][1];tmp=c[z][0];c[z][0]=0;
			pushup(z);pushup(rt);
			splay(t[y][0],rt);
			splay(findmin(c[rt][1]),c[rt][1]);
			z=c[rt][1];c[z][0]=tmp;fa[tmp]=z;
			pushup(z);pushup(rt);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值