树链剖分模板

树剖大法好!!!!!!

#include<bits/stdc++.h>
#define maxn 500005

using namespace std;

struct edge
{
	int pre,to;
}e[maxn*2];
int n,m,root,mod,a[maxn],b[maxn],head[maxn],cnt=0,fa[maxn],dep[maxn],son[maxn],size[maxn],top[maxn],id[maxn];
int ndnum=0,lson[maxn],rson[maxn],sum[maxn],L,R,add[maxn];
void add_edge(int x,int y)
{
	e[++cnt].pre=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}

void dfs1(int x,int father,int depth)
{
	int ans=-1;
	size[x]=1;
	dep[x]=depth;
	fa[x]=father;
	for(int i=head[x];i;i=e[i].pre)
	{
		int v=e[i].to;
		if(v==father) continue;
		dfs1(v,x,depth+1);
		size[x]+=size[v];
		if(size[v]>ans)
		ans=size[v],son[x]=v;
	}
}

void dfs2(int x,int topf)
{
	id[x]=++cnt;
	a[cnt]=b[x];
	top[x]=topf;
	if(son[x]==0) return;
	dfs2(son[x],topf);
	for(int i=head[x];i;i=e[i].pre)
	{
		int v=e[i].to;
		if(v==fa[x]||v==son[x]) continue;
		dfs2(v,v);
	}
}
//树剖; 
void down(int t,int l,int r)
{
	if(add[t]!=0)
	{
		int mid=(l+r)>>1;
		sum[lson[t]]+=(mid-l+1)*add[t];
		sum[lson[t]]%=mod;
		sum[rson[t]]+=(r-mid)*add[t];
		sum[rson[t]]%=mod;
		add[lson[t]]+=add[t];
		add[rson[t]]+=add[t];
		add[t]=0;
	}
} 
void build(int &t,int l,int r)
{
	t=++ndnum;
	if(l==r)
	{
		sum[t]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(lson[t],l,mid);
	build(rson[t],mid+1,r);
	sum[t]=sum[lson[t]]+sum[rson[t]];
}

void modify(int t,int l,int r,int val)
{
	if(l>=L&&r<=R)
	{
		sum[t]+=(r-l+1)*val;
		add[t]+=val;
		return;
	}
	down(t,l,r);
	int mid=(l+r)>>1;
	if(mid>=L) modify(lson[t],l,mid,val);
	if(mid<R) modify(rson[t],mid+1,r,val);
	sum[t]=sum[lson[t]]+sum[rson[t]];
}

int query(int t,int l,int r)
{
	int ans=0;
	if(l>=L&&r<=R)
	return sum[t];
	down(t,l,r);
	int mid=(l+r)>>1;
	if(L<=mid)
	ans+=query(lson[t],l,mid);
	if(R>mid)
	ans+=query(rson[t],mid+1,r);
	return ans%mod;
}
//线段树;
void modify_edge(int x,int y,int val)//x到top[x]中的节点在线段树上是连续的
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		L=id[top[x]];R=id[x];modify(1,1,n,val);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	L=id[x];R=id[y];modify(1,1,n,val);
}

int query_edge(int x,int y)
{
	int ans=0; 
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		L=id[top[x]];R=id[x];ans=(ans+query(1,1,n))%mod;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	L=id[x];R=id[y];ans=(ans+query(1,1,n))%mod;
	return ans%mod;
}

void modify_tree(int x,int val)//以i为根的子树的树在线段树上的编号为[i,i+子树节点数-1]
{
	L=id[x];R=id[x]+size[x]-1;
	modify(1,1,n,val);
}

int query_tree(int x)
{
	L=id[x];R=id[x]+size[x]-1;
	return query(1,1,n)%mod;
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&root,&mod);
	for(int i=1;i<=n;i++)
	scanf("%d",&b[i]);
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add_edge(x,y);
		add_edge(y,x);
	}
	dfs1(root,0,1);
	cnt=0;
	dfs2(root,root);
	int R=0;
	build(R,1,n);
	for(int i=1;i<=m;i++)
	{
		int op,x,y,z;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d%d",&x,&y,&z);
			modify_edge(x,y,z);
		}
		else if(op==2)
		{
			scanf("%d%d",&x,&y);
			printf("%d\n",query_edge(x,y));
		}
		else if(op==3)
		{
			scanf("%d%d",&x,&z);
			modify_tree(x,z);
		}
		else
		{
			scanf("%d",&x);
			printf("%d\n",query_tree(x));
		}
	}
	return 0;
}
/*
5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值