[xsy1019]小A学树论

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[xsy1019]小A学树论相关的知识,希望对你有一定的参考价值。

题意:维护一棵带点权的树,支持查询子树权值和,子树整体增值,换父亲

复习splay

刚开始做的时候智障了,这道题其实直接用splay维护出栈入栈序列就好了

#include<stdio.h>
struct edge{
	int to,nex;
}e[200010];
#define ll long long
int fa[200010],ch[200010][2],siz[200010],nv[100010],h[100010],in[100010],out[100010],M,rt,tot;
ll v[200010],ad[200010],sum[200010];
#define ls ch[x][0]
#define rs ch[x][1]
void add(int a,int b){
	tot++;
	e[tot].to=b;
	e[tot].nex=h[a];
	h[a]=tot;
}
void dfs(int f,int x){
	in[x]=++M;
	for(int i=h[x];i;i=e[i].nex){
		if(e[i].to!=f)dfs(x,e[i].to);
	}
	out[x]=++M;
}
void pushup(int x){
	sum[x]=v[x]+sum[ls]+sum[rs];
	siz[x]=siz[ls]+siz[rs]+1;
}
int build(int l,int r){
	int mid=(l+r)>>1;
	if(l<mid){
		ch[mid][0]=build(l,mid-1);
		fa[ch[mid][0]]=mid;
	}
	if(mid<r){
		ch[mid][1]=build(mid+1,r);
		fa[ch[mid][1]]=mid;
	}
	pushup(mid);
	return mid;
}
void rot(int x){
	int y,z,f,B;
	y=fa[x];
	z=fa[y];
	if(y==rt)rt=x;
	f=ch[y][0]==x;
	B=ch[x][f];
	fa[x]=z;
	fa[y]=x;
	if(B)fa[B]=y;
	ch[x][f]=y;
	ch[y][f^1]=B;
	if(ch[z][0]==y)ch[z][0]=x;
	if(ch[z][1]==y)ch[z][1]=x;
	pushup(y);
	pushup(x);
}
void plus(int x,ll d){
	sum[x]+=siz[x]*d;
	ad[x]+=d;
	v[x]+=d;
}
void pushdown(int x){
	if(ad[x]){
		if(ls)plus(ls,ad[x]);
		if(rs)plus(rs,ad[x]);
		ad[x]=0;
	}
}
void gao(int x){
	if(fa[x])gao(fa[x]);
	pushdown(x);
}
void splay(int x,int gl){
	gao(x);
	int y,z;
	while(fa[x]!=gl){
		y=fa[x];
		z=fa[y];
		if(z!=gl)rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
		rot(x);
	}
}
int presc(int x){
	splay(x,0);
	x=ls;
	while(rs)x=rs;
	return x;
}
int nexsc(int x){
	splay(x,0);
	x=rs;
	while(ls)x=ls;
	return x;
}
int sub(int x){
	int p=presc(in[x]),n=nexsc(out[x]);
	if(p==0){
		if(n==0)return rt;
		splay(n,0);
		return ch[n][0];
	}
	splay(p,0);
	if(n==0)return ch[p][1];
	splay(n,p);
	return ch[n][0];
}
ll query(int x){return sum[sub(x)]>>1;}
void modify(int x,ll v){plus(sub(x),v);}
void change(int x,int y){
	int s=sub(x);
	x=fa[s];
	if(ls==s)ls=0;
	if(rs==s)rs=0;
	while(x){
		pushup(x);
		x=fa[x];
	}
	x=nexsc(in[y]);
	splay(x,in[y]);
	fa[s]=x;
	ls=s;
	while(x){
		pushup(x);
		x=fa[x];
	}
}
int main(){
	int n,m,i,x,y;
	ll d;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",nv+i);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(0,1);
	for(i=1;i<=n;i++)v[in[i]]=v[out[i]]=nv[i];
	rt=build(1,M);
	while(m--){
		scanf("%d",&i);
		if(i==1){
			scanf("%d",&x);
			printf("%lld\n",query(x));
		}
		if(i==2){
			scanf("%d%lld",&x,&d);
			modify(x,d);
		}
		if(i==3){
			scanf("%d%d",&x,&y);
			change(x,y);
		}
	}
}

以上是关于[xsy1019]小A学树论的主要内容,如果未能解决你的问题,请参考以下文章

关于树论左偏树

关于树论主席树

android小知识点代码片段

Android课程---Android Studio使用小技巧:提取方法代码片段

学树链剖分记

微信小程序代码片段