树链剖分

学了2天的树链剖分终于搞懂了,不容易啊~~~~(>_<)~~~~

洛谷的3384是一道很好的模板题

传送门:https://www.luogu.org/problem/show?pid=3384#sub

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 500005
using namespace std;
int n,m,R,P,x,y,z,t;
long long d[N],ee[N],real[N];
int heavyson[N],depth[N],head[N],id[N],father[N],son[N],b[N*4],c[N*4],a[N],top[N];
struct Edge{
	int next,to;
}e[N];
int kk=0;
void add(int x,int y)
{
	kk++;
	e[kk].next=head[x];
	e[kk].to=y;
	head[x]=kk;
}
void build(int k,int x,int y)
{
	b[k]=x; c[k]=y;
	if (x==y){
		d[k]=a[real[x]];
		return;
	}
	int mid=(x+y)/2;
	build(k*2,x,mid);
	build(k*2+1,mid+1,y);
	d[k]=d[k*2]+d[k*2+1];
}
void maintain(int k)
{
	ee[k*2]=ee[k*2]+ee[k];
	ee[k*2+1]=ee[k*2+1]+ee[k];
	d[k*2]=d[k*2]+ee[k]*(c[k*2]-b[k*2]+1);
	d[k*2+1]=d[k*2+1]+ee[k]*(c[k*2+1]-b[k*2+1]+1);
	ee[k]=0;
}
long long sum(int k,int x,int y)
{
	if (x==b[k]&&y==c[k]) return d[k];
	if (ee[k]) maintain(k);
	int mid=(b[k]+c[k])/2;
	if (y<=mid) return sum(k*2,x,y);
	if (x>mid) return sum(k*2+1,x,y);
	if (x<=mid&&y>mid) return sum(k*2+1,mid+1,y)+sum(k*2,x,mid);
}
void addd(int k,int x,int y,int z)
{
	if (x>c[k]||y<b[k]) return;
	if (x<=b[k]&&y>=c[k]){
		ee[k]=ee[k]+z;
		d[k]=d[k]+z*(c[k]-b[k]+1);
		return;
	}
	if (ee[k]) maintain(k);
	int mid=(b[k]+c[k])/2;
	if (y<=mid) addd(k*2,x,y,z);
	else if (x>mid) addd(k*2+1,x,y,z);
	else if (x<=mid&&y>mid){
		addd(k*2,x,mid,z);
		addd(k*2+1,mid+1,y,z);
	}
	d[k]=d[k*2]+d[k*2+1];
	return;
}
void Dfs1(int now,int fa)
{
	father[now]=fa;
	depth[now]=depth[fa]+1;
	son[now]=1;
	for (int i=head[now];i;i=e[i].next){
		if (e[i].to!=fa){
			Dfs1(e[i].to,now);
			son[now]=son[now]+son[e[i].to];
			if (heavyson[now]==0||son[e[i].to]>son[heavyson[now]]) heavyson[now]=e[i].to;
		}
	}
}
int temp=0;
void Dfs2(int u,int first)
{
	top[u]=first;
	temp++;
	id[u]=temp;
	real[temp]=u;
	if (!heavyson[u]) return;
	Dfs2(heavyson[u],first);
	for (int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if (v!=heavyson[u]&&v!=father[u]) Dfs2(v,v);
	}
}
long long find(int u,int v)
{
	long long sum1=0;
	int tou=top[u];
	int tov=top[v];
	while (tou!=tov){
		if (depth[tou]<depth[tov]) swap(u,v),swap(tou,tov);
		sum1=sum1+sum(1,id[tou],id[u]);
		sum1=sum1%P;
		u=father[tou];
		tou=top[u];
	}
	if (depth[u]>depth[v]) swap(u,v);
	sum1=sum1+sum(1,id[u],id[v]);
	return sum1%P;
}
void change(int u,int v,int z)
{
	int tou=top[x];
	int tov=top[y];
	while (tou!=tov){
		if (depth[tou]<depth[tov]) swap(u,v),swap(tou,tov);
		addd(1,id[tou],id[u],z);
		u=father[tou];
		tou=top[u];	
	}
	if (depth[u]>depth[v]) swap(u,v);
	addd(1,id[u],id[v],z);
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&R,&P);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	Dfs1(R,0);
	Dfs2(R,R);
	build(1,1,n);
	for (int i=1;i<=m;i++){
		scanf("%d",&t);
		if (t==1){
			scanf("%d%d%d",&x,&y,&z);
			change(x,y,z);
		}
		if (t==2){
			scanf("%d%d",&x,&y);
			printf("%lld\n",find(x,y));
		}
		if (t==3){
			scanf("%d%d",&x,&y);
			addd(1,id[x],id[x]+son[x]-1,y);
		}
		if (t==4){
			scanf("%d",&x);
			printf("%lld\n",sum(1,id[x],id[x]+son[x]-1)%P); 
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值