(模板)树链剖分

(模板)树链剖分

大佬博客

题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

  • dfs1处理出重儿子,子树大小,父亲,深度
  • dfs2新标号,所在链顶端(用老标号)
  • 然后以新标号为下标开线段树

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;

inline int read()
{
	int x=0,f=1; char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return f*x;
}
typedef long long LL;
#define res register int
const int N=1e5+5;
int head[N],ver[N<<1],nxt[N<<1];
int n,m,tot,r;
LL w[N],P;
inline void add(int x,int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}

int fa[N],dep[N],siz[N],son[N];
/*
Ê÷Á´ÆÊ·Ö£º
1. dfs1 ´¦ÀíÉî¶È£¬Öضù×Ó£¬×ÓÊ÷´óС£¬¸¸Ç× 
2. dfs2 бàºÅ£¬¸´ÖƵãȨ£¬¼Ç¼ÿÌõÖØÁ´µÄ¶¥¶Ë 
3.Ï߶ÎÊ÷´¦ÀíÁ¬ÐøÇø¼äºÍ 
*/
void dfs1(int x,int f)
{
	fa[x]=f; dep[x]=dep[f]+1;
	siz[x]=1;
	for(res i=head[x] ; i ; i=nxt[i])
	{
		int y=ver[i];
		if(y==f) continue;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]]) son[x]=y;
	}
}

int num=0,id[N],top[N];
LL val[N];
void dfs2(int x,int topf)
{
	id[x]=++num; val[num]=w[x];
	top[x]=topf;
	if(!son[x]) return ;
	dfs2(son[x],topf);//ÓÅÏÈ´¦ÀíÖضù×Ó 
	for(res i=head[x] ; i ; i=nxt[i])
	{
		int y=ver[i]; if(y==son[x]||y==fa[x]) continue;
		dfs2(y,y);
	}
}
//Ï߶ÎÊ÷£º
LL tag[N<<2],sum[N<<2];
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
inline void pushup(int p)
{sum[p]=(sum[p<<1]+sum[p<<1|1]+P)%P;}
inline void build(int p,int l,int r)
{
	if(l==r) {
		sum[p]=val[l]; return ;
	}
	int mid=(l+r)>>1;
	build(lson); build(rson);
	pushup(p);	
}
inline void pushdown(int p,int l,int r,int mid)
{	
	sum[p<<1]=(sum[p<<1]+(mid-l+1)*tag[p]+P)%P;
	sum[p<<1|1]=(sum[p<<1|1]+(r-mid)*tag[p]+P)%P;
	tag[p<<1]=(tag[p<<1]+tag[p]+P)%P;
	tag[p<<1|1]=(tag[p<<1|1]+tag[p]+P)%P;
	tag[p]=0;
}

inline LL query(int p,int l,int r,int ql,int qr)
{
	if(ql>qr) swap(ql,qr);
	if(ql<=l && r<=qr) return sum[p];
	int mid=(l+r)>>1;
	pushdown(p,l,r,mid);
	LL ret=0;
	if(ql<=mid) ret=query(lson,ql,qr)%P;
	if(qr>mid) ret=(query(rson,ql,qr)+P+ret)%P;
	return ret;
}

inline void change(int p,int l,int r,int ql,int qr,LL k)
{
	if(qr<ql) swap(ql,qr);
	if(ql<=l && r<=qr)
	{
		sum[p]+=(LL)(r-l+1)*k; 
		tag[p]+=k;
		return;
	}
	int mid=(l+r)>>1;
	pushdown(p,l,r,mid);
	if(ql<=mid) change(lson,ql,qr,k);
	if(qr>mid) change(rson,ql,qr,k);
	pushup(p);
}
//end 
inline LL qson(int p) {
	return query(1,1,n,id[p],id[p]+siz[p]-1);
}
inline void cson(int p,int k) {
	change(1,1,n,id[p],id[p]+siz[p]-1,k);
}
//²éѯʱÏÈÕÒËùÔÚÁ´µÄ¶¥µã×îÉîµÄ£¬È»ºó²»¶ÏÍùÉÏÌø
inline LL qrange(int x,int y)
{
	LL ret=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);//ÈÃx¸üÉî
		ret=(query(1,1,n,id[top[x]],id[x])+ret+P)%P;
		x=fa[top[x]]; 
	}
	if(dep[x]<dep[y]) swap(x,y);
	ret=(ret+P+query(1,1,n,id[y],id[x]))%P;
	return ret;
}

inline void crange(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		change(1,1,n,id[top[x]],id[x],k);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	change(1,1,n,id[y],id[x],k);
}

int main()
{
//	freopen("in.txt","r",stdin);
	n=read(); m=read(); r=read(); P=read();
	for(res i=1 ; i<=n ; ++i) w[i]=read();
	for(res i=1 ; i<n ; ++i) {
		int x=read(),y=read(); 
		add(x,y); add(y,x);
	}
	dfs1(r,0);
	dfs2(r,r); 
	build(1,1,n);
	int x,y,k,op;
	for(res i=1 ; i<=m ; ++i)
	{
		op=read();
		if(op==1)
		{
			x=read(); y=read(); k=read();
			crange(x,y,k);
		}
		else if(op==2)
		{
			x=read(); y=read();
			printf("%lld
",qrange(x,y));
		}
		else if(op==3)
		{
			x=read(); k=read();
			cson(x,k); 
		}
		else
		{
			x=read(); 
			printf("%lld
",qson(x));
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/wmq12138/p/10625187.html