Loading

ETT小记

一个很简单的东西。

题意:一棵树,有点权。多次操作,支持子树加,单点换父亲,查询到根路径权值和。

\(1\le n\le 10^5,\space 1\le m\le 3\times 10^5\)

考虑维护树的欧拉序,就是一个点访问和回溯的时候往后加入序列末尾。

子树加法就是区间加,换父亲就是区间平移,使用平衡树解决,注意一个点的权值带符号。

写了 treap,随机 merge 没过,只好改成随机堆权,发现常数是原来的 \(\dfrac 13\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,ll>
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
using namespace std;
const ll maxn=2e5+10, mod=998244353;
mt19937 rnd(time(0));
struct Treap{
	ll lc[maxn],rc[maxn],val[maxn],sum[maxn],siz[maxn],fa[maxn],tag[maxn],cnt[maxn],ff[maxn],rd[maxn];
	void pushup(ll p){
		sum[p]=sum[lc[p]]+sum[rc[p]]+val[p];
		siz[p]=siz[lc[p]]+siz[rc[p]]+1;
		cnt[p]=cnt[lc[p]]+cnt[rc[p]]+ff[p];
		fa[lc[p]]=fa[rc[p]]=p;
		fa[0]=0;
	}
	void addtag(ll p,ll v){
		if(!p) return;
		val[p]+=v*ff[p], tag[p]+=v, sum[p]+=v*cnt[p];
	}
	void pushdown(ll p){
		if(!tag[p]) return;
		addtag(lc[p],tag[p]), addtag(rc[p],tag[p]);
		tag[p]=0;
	}
	void split(ll p,ll k,ll &x,ll &y){
		if(!p){
			x=y=0; return;
		} pushdown(p);
		if(siz[lc[p]]+1<=k){
			x=p, fa[rc[p]]=0;
			split(rc[p],k-siz[lc[p]]-1,rc[x],y);
			pushup(x);
		} else{
			y=p, fa[lc[p]]=0;
			split(lc[p],k,x,lc[y]);
			pushup(y);
		}
	}
	ll merge(ll p,ll q){
		if(!p||!q) return p|q;
		pushdown(p), pushdown(q);
		if(rd[p]<rd[q]){
			fa[rc[p]]=0;
			rc[p]=merge(rc[p],q);
			pushup(p); return p;
		} else{
			fa[lc[q]]=0;
			lc[q]=merge(p,lc[q]);
			pushup(q); return q;
		}
	}
	void init(ll p,ll v,ll f){
		sum[p]=val[p]=v, cnt[p]=ff[p]=f, tag[p]=lc[p]=rc[p]=fa[p]=0, siz[p]=1;
		rd[p]=rnd()%(1ll<<31);
	}
	ll getrk(ll p){
		ll res=1+siz[lc[p]];
		while(fa[p]){
			if(rc[fa[p]]==p) res+=siz[lc[fa[p]]]+1;
			p=fa[p];
		} return res;
	}
	void renew(ll p){
		if(fa[p]) renew(fa[p]);
		pushdown(p);
	}
	ll query(ll p){
		renew(p);
		ll res=val[p]+sum[lc[p]];
		while(fa[p]){
			if(rc[fa[p]]==p) res+=sum[lc[fa[p]]]+val[fa[p]];
			p=fa[p];
		} return res;
	}
}T;
ll n,a[maxn],m,x,y,rt;
char op[4];
vector<ll>to[maxn];
void dfs(ll u){
	T.init(u,a[u],1);
	rt=T.merge(rt,u);
	for(ll v:to[u]){
		dfs(v);
	}
	T.init(u+n,-a[u],-1);
	rt=T.merge(rt,u+n);
}
ll s1,s2,s3,s;
int main(){
	scanf("%lld",&n);
	for(ll i=2,x;i<=n;i++){
		scanf("%lld",&x); to[x].pb(i);
	}
	for(ll i=1;i<=n;i++) scanf("%lld",a+i);
	dfs(1);
	scanf("%lld",&m);
	T.getrk(16932);
	while(m--){
		scanf("%s%lld",op,&x);
		if(op[0]=='Q') printf("%lld\n",T.query(x));
		else if(op[0]=='C'){ scanf("%lld",&y);
			ll l=T.getrk(x), r=T.getrk(x+n);
			ll t=T.getrk(y);
			T.split(rt,r,s1,s3);
			T.split(s1,l-1,s1,s);
			if(t<l){
				T.split(s1,t,s1,s2); T.fa[s1]=T.fa[s2]=T.fa[s3]=T.fa[s]=0;
				rt=T.merge(T.merge(s1,s),T.merge(s2,s3));
			} else{
				T.split(s3,t-r,s2,s3); T.fa[s1]=T.fa[s2]=T.fa[s3]=T.fa[s]=0;
				rt=T.merge(T.merge(s1,s2),T.merge(s,s3));
			}
		} else{
			scanf("%lld",&y);
			ll l=T.getrk(x), r=T.getrk(x+n);
			T.split(rt,r,s1,s3);
			T.split(s1,l-1,s1,s2);
			T.addtag(s2,y);
			rt=T.merge(T.merge(s1,s2),s3);// T.fa[rt]=0;
		}
	}
	return 0;
}
posted @ 2024-03-04 18:46  Lgx_Q  阅读(20)  评论(0编辑  收藏  举报