ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Luogu-P3384 【模板】轻重链剖分/树链剖分

2021-09-14 11:03:47  阅读:230  来源: 互联网

标签:链剖分 剖分 int Luogu long tag Ha id LX


学习

是看这篇博文学习的。
https://www.cnblogs.com/chinhhh/p/7965433.html

代码

#include <bits/stdc++.h>
using namespace std;

#define MAXN 100005

long long Ha;
int n,m,root;
vector<int> graph[MAXN];


int siz[MAXN];
int son[MAXN];
int fa[MAXN];
int dep[MAXN];
int top[MAXN];
int id[MAXN];
int cnt;
int rk[MAXN];

long long w[MAXN];



struct segment_tree {
	#define LX (X<<1)
	#define RX ((X<<1)|1)
	static const int _MAXN=MAXN;
	
	struct node {
		long long s;
		int l,r,len;
		long long tag;
	} a[_MAXN<<3];
	
	void build(int X, int l, int r) {
		a[X].l=l;
		a[X].r=r;
		a[X].len=r-l+1;
		a[X].tag=0;
		if (l==r) {
			a[X].s=w[rk[l]];
			return;
		}
		build(LX, l, (l+r)>>1);
		build(RX, ((l+r)>>1)+1, r);
		a[X].s=a[LX].s+a[RX].s;
		a[X].s%=Ha;
	}
	
	void down_tag(int X) {
		a[LX].s+=a[X].tag*a[LX].len %Ha, a[LX].s%=Ha;
		a[LX].tag+=a[X].tag, a[LX].tag%=Ha;
		a[RX].s+=a[X].tag*a[RX].len %Ha, a[RX].s%=Ha;
		a[RX].tag+=a[X].tag, a[RX].tag%=Ha;
		a[X].tag=0;
	}
	
	void modify_add(int X, int L, int R, int V)	{
		if (a[X].l>=L && a[X].r<=R) {
			a[X].s+=V*a[X].len %Ha; a[X].s%=Ha;
			a[X].tag+=V; a[X].tag%=Ha;
			return;
		}
		down_tag(X);
		if (a[LX].r>=L) modify_add(LX, L, R, V);
		if (a[RX].l<=R) modify_add(RX, L, R, V);
		a[X].s=(a[LX].s+a[RX].s) %Ha;
	}
	
	long long query_sum(int X, int L, int R) {
		if (a[X].l>=L && a[X].r<=R) {
			return a[X].s;
		}
		long long ret=0;
		down_tag(X);
		if (a[LX].r>=L) ret+=query_sum(LX, L, R);
		if (a[RX].l<=R) ret+=query_sum(RX, L, R);
		
		return ret%Ha;
	}
	
} SegT;



//第一次dfs,计算 fa\dep\size\son 
void dfs1(int X, int Fa)	//(当前节点,父节点)
{
	fa[X]=Fa;
	dep[X]=dep[Fa]+1;
	siz[X]=1;
	int mxsiz=0,mxX=0;
	for (int &o: graph[X]) if (o!=Fa) {
		dfs1(o, X);
		siz[X]+=siz[o];
		if (siz[o]>mxsiz) {
			mxsiz=siz[o];
			mxX=o;
		}
	}
	son[X]=mxX;
}


//第二次dfs,计算 top\id\rk 
void dfs2(int X, int Fa, int T)		//(当前节点,父节点,所在链的顶端节点)
{
	top[X]=T;
	id[X]=++cnt;
	rk[cnt]=X;
	
	if (son[X])
		dfs2(son[X], X, T);		//重儿子 
	
	for (int &o: graph[X]) if (o!=Fa && o!=son[X])
		dfs2(o, X, o);		//普通儿子 
}


void init()
{
	dfs1(root,0);
	dfs2(root,0,root);
	SegT.build(1,0,n);
}


int main()
{
	//freopen("P3384_2.in","r",stdin);
	scanf("%d%d%d%lld",&n,&m,&root,&Ha);
	for (int i=1; i<=n; i++) scanf("%lld",&w[i]);
	for (int i=1,uu,vv; i<n; i++) {
		scanf("%d%d",&uu,&vv);
		graph[uu].push_back(vv);
		graph[vv].push_back(uu);
	}
	
	init();
	
	for (int ttt=1,opr,x,y,z; ttt<=m; ttt++) {
		scanf("%d",&opr);
		
		if (opr==1) {	//路径加 
			
			scanf("%d%d%d",&x,&y,&z);
			while (top[x]!=top[y]) {
				if (dep[top[x]]<dep[top[y]]) swap(x,y);	//让 x 为 top 更深的那个点 
				SegT.modify_add(1, id[top[x]], id[x], z);	//跳上去,区间加 
				x=fa[top[x]];
			}
			//此时 xy 处于同一条链上,路径 x->y 为一段连续区间 
			if (dep[x]>dep[y]) swap(x,y);
			SegT.modify_add(1, id[x], id[y], z);
			
		}
		else if (opr==2) {	//路径求和 
			
			scanf("%d%d",&x,&y);
			long long ans=0;
			while (top[x]!=top[y]) {
				if (dep[top[x]]<dep[top[y]]) swap(x,y);
				ans+= SegT.query_sum(1, id[top[x]], id[x]);
				ans%=Ha;
				x=fa[top[x]];
			}
			if (dep[x]>dep[y]) swap(x,y);
			ans+= SegT.query_sum(1, id[x],id[y]);
			ans%=Ha;
			printf("%lld\n",ans);
			
		}
		else if (opr==3) {	//子树加 
			
			scanf("%d%d",&x,&z);
			SegT.modify_add(1, id[x], id[x]+siz[x]-1, z);
			
		}
		else if (opr==4) {	//子树求和 
			
			scanf("%d",&x);
			printf("%lld\n",SegT.query_sum(1, id[x], id[x]+siz[x]-1));
			
		}
	}
	
	return 0;
}

/*

4 6 1 998244353
0 0 2 4 
2 1
3 1
4 1
3 3 1
1 2 3 1
2 1 1
4 1
1 1 4 6
2 3 1



8 10 2 448348
458 718 447 857 633 264 238 944 
1 2
2 3
3 4
6 2
1 5
5 7
8 6
3 7 611
4 6
3 1 267
3 2 111
1 6 3 153
3 7 673
4 8
2 6 1
4 7
3 4 228


8 10 2 448348
0 0 0 0 0 0 0 0
1 2
2 3
3 4
6 2
1 5
5 7
8 6
3 7 1
4 6
3 1 1
3 2 1
1 6 3 1
3 7 1
4 8
2 6 1
4 7
3 4 1


*/

标签:链剖分,剖分,int,Luogu,long,tag,Ha,id,LX
来源: https://blog.csdn.net/jackypigpig/article/details/120283104

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有