BZOJ#3786. 星系探索(平衡树,fhq-treap,弱化版ETT)

BZOJ#3786. 星系探索

Solution

子树加,换 f a t h e r father father(保证还是树),询问到根路径和。
树上路径求和不好动态维护,于是转化到序列上,维护一个括号序, d f n dfn dfn处贡献为 w w w f n s fns fns处贡献为 − w -w w,一段路径 ( x , y ) (x,y) (x,y)的和相当于序列上 d f n x dfn_x dfnx d f n y dfn_y dfny的贡献和。

于是子树加相当于区间加,交换子树相当于在括号序上取出一个区间插入到其他地方去。
这个可以直接用平衡树维护,这里用的是 f h q − t r e a p fhq-treap fhqtreap

我们在 f h q − t r e a p fhq-treap fhqtreap中节点的下标对应的是原树的括号序编号,即 d f n x dfn_x dfnx t r e a p treap treap上对应 d f n x dfn_x dfnx号节点,在 s p l i t split split时,当前的括号序为中序遍历 t r e a p treap treap后得到的节点编号序列。需要求出节点在 t r e a p treap treap上的 r a n k rank rank,然后再按 r a n k rank rank分成两棵子树。

剩下的就是 t r e a p treap treap的区间标记维护区间和了(注意 d f n x + = Δ dfn_x+=\Delta dfnx+=Δ,则 f n s x − = Δ fns_x-=\Delta fnsx=Δ,因此我们的区间和要带符号维护)。

时间复杂度 O ( n l g n ) O(nlgn) O(nlgn)

Code

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

using namespace std;

template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;

const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
struct fhq_treap
{
	ll a[MAXN],sum[MAXN],tag[MAXN];
	int b[MAXN],sz[MAXN],p[MAXN],num[MAXN],fa[MAXN],ch[MAXN][2],rt;
	void up(int x) 
	{ 
		sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
		num[x]=num[ch[x][0]]+num[ch[x][1]]+p[x];
		sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+a[x]; 
		if (ch[x][0]) fa[ch[x][0]]=x;
		if (ch[x][1]) fa[ch[x][1]]=x;
	}
	void puttag(int x,ll y) 
	{ 
		if (!x) return; 
		tag[x]+=y,a[x]+=y*p[x],sum[x]+=y*num[x]; 
	}
	void down(int x) 
	{ 
		if (!x||tag[x]==0) return;
		puttag(ch[x][0],tag[x]),puttag(ch[x][1],tag[x]),tag[x]=0;
	}
	int nwnode(int id,int opt,int x) 
	{ 
		p[id]=num[id]=opt;
		a[id]=sum[id]=opt*x;
		b[id]=rand(),sz[id]=1; 
		return id; 
	}
	void split(int nw,int k,int &x,int &y)
	{
		if (!nw) x=y=0;
		else
		{
			down(nw);
			if (k<=sz[ch[nw][0]]) y=nw,split(ch[nw][0],k,x,ch[nw][0]);
			else x=nw,split(ch[nw][1],k-sz[ch[nw][0]]-1,ch[nw][1],y);
			up(nw);
		}
	}
	int merge(int x,int y)
	{
		if (!x||!y) return x|y;
		down(x),down(y);
		if (b[x]<b[y]) return ch[x][1]=merge(ch[x][1],y),up(x),x;
		else return ch[y][0]=merge(x,ch[y][0]),up(y),y;
	}
	int rank(int x)
	{
		int rk=sz[ch[x][0]]+1;
		while (fa[x]) 
		{
			if (x==ch[fa[x]][1]) rk+=sz[ch[fa[x]][0]]+1;
			x=fa[x];
		}
		return rk;
	}
	
	
	ll Query(int x)
	{
		int A,B;
		split(rt,rank(x),A,B);
		ll ans=sum[A];
		rt=merge(A,B);
		return ans;
	}
	void Swap(int l,int r,int x)
	{
		int A,B,C,D;
		l=rank(l),r=rank(r),x=rank(x);
		if (x<=l-1)  //1...x...l...r...n
		{
			split(rt,r,A,D);
			split(A,l-1,A,B);
			split(A,x,A,C);
			rt=merge(merge(merge(A,B),C),D);
		}
		else
		{
			split(rt,x,A,D); //1...l...r...x...n
			split(A,r,A,B);
			split(A,l-1,A,C);
			rt=merge(merge(merge(A,B),C),D);
		}
	}
	void Update(int l,int r,int y)
	{
		int A,B,C;
		l=rank(l),r=rank(r);
		split(rt,r,A,C);
		split(A,l-1,A,B);
		puttag(B,y);
		rt=merge(merge(A,B),C);
	}
} T;
vector<int> e[MAXN];
int dfn[MAXN],fns[MAXN],w[MAXN],DFN=0;
void dfs(int x,int father)
{
	dfn[x]=++DFN;
	T.rt=T.merge(T.rt,T.nwnode(DFN,1,w[x]));
	for (auto v:e[x]) if (v!=father) dfs(v,x);
	fns[x]=++DFN;
	T.rt=T.merge(T.rt,T.nwnode(DFN,-1,w[x]));
}
signed main()
{
	srand(time(0));
	int n=read();
	for (int i=2;i<=n;i++) e[read()].PB(i);
	for (int i=1;i<=n;i++) w[i]=read();
	dfs(1,0);
	int Case=read();
	while (Case--)
	{
		int x,y; char c; 
		scanf("%c",&c);
		if (c=='Q') x=read(),printf("%lld\n",T.Query(dfn[x]));
		else if (c=='C') x=read(),y=read(),T.Swap(dfn[x],fns[x],dfn[y]);
		else x=read(),y=read(),T.Update(dfn[x],fns[x],y);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值