星系探索 黑暗爆炸 - 3786[LCT][平衡树]

文章目录

题目

3e5
维护操作:子树加,换父亲、 u u u 到根路径和

思路

借助欧拉序和平衡树可实现子树平移,具体 u u u v v v 就是将 [ i n u , o u t u ] [in_u,out_u] [inu,outu] 接到 i n v in_v inv 后面
到根路径和类似带修改树上第 k k k 大, i n u in_u inu + + + o u t u out_u outu 处-
需要维护欧拉序上子树内多少个 ( ( ( 括号
LCT 可用标记永久化

代码

#include<set>  
#include<map>  
#include<stack>  
#include<cmath>  
#include<cstdio>  
#include<queue>  
#include<vector>  
#include<climits>  
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;     
int read(){     
    bool f=0;int 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 !f?x:-x;    
}
const int MAXN=300000;
const int INF=0x3f3f3f3f;
LL sum[MAXN+5],val[MAXN+5],lazy[MAXN+5];
int ncnt,Root,ch[MAXN+5][2],fa[MAXN+5],cnt[MAXN+5],csiz[MAXN+5],siz[MAXN+5];
bool pan(int u){return ch[fa[u]][1]==u;}
void Init(){
	Root=0,ncnt=0;
	return ;
}
int Newnode(int u){
	sum[u]=val[u]=lazy[u]=0,ch[u][0]=ch[u][1]=fa[u]=0,siz[u]=1,csiz[u]=cnt[u];
	return u;
}
void PushUp(int u){
	siz[u]=siz[ch[u][0]]+siz[ch[u][1]]+1;
	sum[u]=sum[ch[u][0]]+sum[ch[u][1]]+val[u];
	csiz[u]=csiz[ch[u][0]]+csiz[ch[u][1]]+cnt[u];
	return ;
}
void PushDown(int u){
	if(!lazy[u]) return ;
	lazy[ch[u][0]]+=lazy[u],lazy[ch[u][1]]+=lazy[u];
	val[ch[u][0]]+=cnt[ch[u][0]]?lazy[u]:-lazy[u],val[ch[u][1]]+=cnt[ch[u][1]]?lazy[u]:-lazy[u];
	sum[ch[u][0]]+=(2*csiz[ch[u][0]]-siz[ch[u][0]])*lazy[u],sum[ch[u][1]]+=(2*csiz[ch[u][1]]-siz[ch[u][1]])*lazy[u];
	lazy[u]=0;
	return ;
}
void Rotate(int x){//修改顺序:父亲,儿子
	int y=fa[x],z=fa[y],dx=pan(x),dy=pan(y);
	fa[x]=z,fa[y]=x;//此时pan(y)改变
	if(ch[x][dx^1]!=0) fa[ch[x][dx^1]]=y;
	if(z!=0) ch[z][dy]=x;
	ch[y][dx]=ch[x][dx^1],ch[x][dx^1]=y;
	PushUp(y);
	return ;
}
void PushAll(int x,int rt){
	if(x!=rt)
		PushAll(fa[x],rt);
	PushDown(x);
	return ;
}
void Splay(int x,int &rt){//任何操作完后必加!!!!功能:将x旋转至rt
	int f=fa[rt];
	PushAll(x,rt);
	for(int y=fa[x];y!=f;Rotate(x),y=fa[x])
		if(fa[y]!=f)
			Rotate(pan(x)==pan(y)?y:x);
	PushUp(x);
	rt=x;
	return ;
}
void Print(int u);
void Select(int k,int &rt){
	int u=rt;
	//Print(u),puts("");
	while(1){
		PushDown(u);
		if(k==siz[ch[u][0]]+1)
			break;
		if(k<=siz[ch[u][0]])
			u=ch[u][0];
		else
			k-=siz[ch[u][0]]+1,u=ch[u][1];
	}
	Splay(u,rt);
	return ;
}
int Merge(int u,int v){
	if(!u||!v) return u+v;
	Select(siz[u],u);
	ch[u][1]=v,fa[v]=u;
	PushUp(u);
	return u;
}
void Split(int rt,int k,int &x,int &y){
	if(!k){
		x=0,y=rt;
		return ;
	}
	Select(k,rt);
	x=rt,y=ch[rt][1];
	ch[x][1]=fa[y]=0;
	PushUp(x);
	return ;
}
void Build(int &u,int L,int R){
	if(L>R) return ;
	int Mid=(L+R)>>1;
	u=Newnode(Mid);
	Build(ch[u][0],L,Mid-1);
	Build(ch[u][1],Mid+1,R);
	if(ch[u][0]) fa[ch[u][0]]=u;
	if(ch[u][1]) fa[ch[u][1]]=u;
	PushUp(u);
	return ;
}
int Getrank(int rt,int u){
	int ret=siz[ch[u][0]]+1;
	while(fa[u]){
		int d=pan(u);
		if(d) ret+=siz[ch[fa[u]][0]]+1; 
		u=fa[u];
	}
	return ret;
}
void Print(int u){
	if(!u) return ;
	putchar('(');
	Print(ch[u][0]);
	printf("%d",u);
	Print(ch[u][1]);
	putchar(')');
	return ;
}
vector<int> G[MAXN+5];
int ocnt,in[MAXN+5],out[MAXN+5];
void DFS(int u){
	in[u]=++ocnt,cnt[in[u]]=1;
	for(int i=0;i<(int)G[u].size();i++)
		DFS(G[u][i]);
	out[u]=++ocnt;
	return ;
}
char Re[5];
LL w[MAXN+5];
int main(){
	int n=read();
	for(int i=2;i<=n;i++)
		G[read()].push_back(i);
	DFS(1);
	Init();
	Build(Root,1,ocnt);
	for(int i=1;i<=n;i++){
		w[i]=read();
		Splay(in[i],Root);
		val[Root]+=w[i],sum[Root]+=w[i];
		Splay(out[i],Root);
		val[Root]-=w[i],sum[Root]-=w[i];
	}
	int m=read();
	for(int i=1;i<=m;i++){
		scanf("%s",Re);
		if(Re[0]=='Q'){
			int u=read(),k=Getrank(Root,in[u]),L,R;
			Split(Root,k,L,R);
			printf("%lld\n",sum[L]);
			Root=Merge(L,R);
		}
		else if(Re[0]=='C'){
			int u=read(),f=read();
			int k1=Getrank(Root,in[u]),k2=Getrank(Root,out[u]),k3,L,Mid,R;
			Split(Root,k2,Mid,R);
			Split(Mid,k1-1,L,Mid);
			Root=Merge(L,R);
			k3=Getrank(Root,in[f]);
			Split(Root,k3,L,R);
			Root=Merge(Merge(L,Mid),R);
		}
		else if(Re[0]=='F'){
			int u=read(),q=read();
			int k1=Getrank(Root,in[u]),k2=Getrank(Root,out[u]),L,Mid,R;
			Split(Root,k2,Mid,R);
			Split(Mid,k1-1,L,Mid);
			lazy[Mid]+=q,val[Mid]+=cnt[Mid]?q:-q;
			sum[Mid]+=(2*csiz[Mid]-siz[Mid])*q;
			Root=Merge(Merge(L,Mid),R);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值