P3384 【模板】樹鏈剖分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
int const MXN=100005;
int n,m,R,MOD,cnt,a[MXN],hd[MXN],fa[MXN],dep[MXN],siz[MXN],b[MXN],son[MXN],id[MXN],T[MXN],tp[MXN];
int x,y;
struct Edge{
	int to,nxt;
}edge[MXN<<1];
void add(int u,int v)
{
	cnt++;
	edge[cnt].to=v;
	edge[cnt].nxt=hd[u];
	hd[u]=cnt;
}
//求深度,父節點 ,重兒子,size[] 
void dfs1(int u,int d,int f)
{
	dep[u]=d;
	siz[u]=1; 
	int mx=0;
	for(int i=hd[u];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v!=f)
		{
			fa[v]=u;
			dfs1(v,d+1,u);
			if(siz[v]>mx)
			{
				mx=siz[v]; 
				son[u]=v;
			}
			siz[u]+=siz[v];	
		}
	}
}
int tot=0;
//將樹映射到線性的線段樹上 ,並求出top[] 
void dfs2(int u,int top)
{
	id[u]=++tot;//原樹上的點在線段樹上的排名 
	a[tot]=b[u];//線段樹上 的權值 
	T[tot]=u;//線段樹的點在原樹上的編號 
	tp[u]=top;//
	if(son[u]!=0)
		dfs2(son[u],top); 
	for(int i=hd[u];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v!=fa[u] && v!=son[u])
		{
//			id[v]=++tot;//少這句話 
//			a[tot]=b[v];
//			T[tot]=v;
//			tp[v]=v;//輕兒子的top就是自己		
			dfs2(v,v);	
		}
	}
}
struct Tree{
	int l,r,sum,ad;
}tre[MXN<<2];
void pushup(int rt)
{
	tre[rt].sum=(tre[rt<<1].sum+tre[rt<<1|1].sum+MOD)%MOD;
}
void build(int rt,int L,int R)
{
	tre[rt].l=L;
	tre[rt].r=R;
	if(L==R)
	{
		tre[rt].sum=a[L];
		return ;
	}
	int mid=(L+R)>>1;
	build(rt<<1,L,mid);
	build(rt<<1|1,mid+1,R);
	pushup(rt);
}
void pushdown(int rt)
{
	if(tre[rt].ad)
	{
		tre[rt<<1].ad+=tre[rt].ad;
		tre[rt<<1|1].ad+=tre[rt].ad;
		tre[rt<<1].sum+=tre[rt].ad*(tre[rt<<1].r-tre[rt<<1].l+1);
		tre[rt<<1|1].sum+=tre[rt].ad*(tre[rt<<1|1].r-tre[rt<<1|1].l+1); 
		tre[rt].ad=0;
	}
}
void update(int rt,int L,int R,int v)
{
	if(L<=tre[rt].l && R>=tre[rt].r)//少一個等於號 
	{
		tre[rt].ad+=v;
		tre[rt].sum +=v*(tre[rt].r-tre[rt].l+1);
		return;
	}
	pushdown(rt);
	int mid=(tre[rt].l+tre[rt].r)>>1;
	if(L<=mid)
		update(rt<<1,L,R,v);
	if(R>mid)
		update(rt<<1|1,L,R,v);
	pushup(rt);
}
int query(int rt,int L,int R)
{
	if(L<=tre[rt].l && R>=tre[rt].r)
		return tre[rt].sum;	
	pushdown(rt);////////////////少寫 
	int mid=(tre[rt].l+tre[rt].r)>>1;
	int tmp=0;
	if(L<=mid)
		tmp=(tmp+query(rt<<1,L,R))%MOD;
	if(R>mid)
		tmp=(tmp+query(rt<<1|1,L,R))%MOD;
	return tmp;
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&R,&MOD);
	for(int i=1;i<=n;i++)
		scanf("%d",&b[i]);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs1(R,1,-1);
//	for(int i=1;i<=n;i++)
//		cout<<dep[i]<<endl; 
	dfs2(R,R);
//	for(int i=1;i<=tot;i++)
//		cout<<T[i]<<" ";

	build(1,1,tot);
//	for(int i=1;i<=2*tot;i++)
//		cout<<tre[i].sum<<",";
//	for(int i=1;i<=n;i++)
//		cout<<id[i]<<",";
	int q,rt,l,r,v;
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&q);
		if(q==1)
		{
			scanf("%d%d%d",&l,&r,&v);
			while(tp[l]!=tp[r])	
			{
				if(dep[tp[l]]<dep[tp[r]])swap(l,r);
				update(1,id[tp[l]],id[l],v);
				l=fa[tp[l]];
			}
//				cout<<tre[1].sum<<endl; 
			if(dep[l]>dep[r]) swap(l,r);
			update(1,id[l],id[r],v);
//			cout<<tre[1].sum<<endl; 
		}
		else if(q==2)
		{
			scanf("%d%d",&l,&r);
			int tmp=0;
			while(tp[l]!=tp[r])
			{
				if(dep[tp[l]]<dep[tp[r]])swap(l,r);
				tmp=(tmp+query(1,id[tp[l]],id[l]))%MOD;
				l=fa[tp[l]];
			}
			if(dep[l]>dep[r])swap(l,r);
			tmp=(tmp+query(1,id[l],id[r]))%MOD;
			printf("%d\n",tmp);
		}
		else if(q==3)
		{
			scanf("%d%d",&rt,&v);
			update(1,id[rt],id[rt]+siz[rt]-1,v);
//			cout<<tre[7].sum<<endl;
		}
		else
		{
			scanf("%d",&rt);
			printf("%d\n",query(1,id[rt],id[rt]+siz[rt]-1));	
		} 
	} 
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章