Luogu 3384(树链剖分)(模板)

传送门

关于树链剖分的复杂度分析:首先对于一条轻边(u,v),可由反证法得出size(v)<size(u)/2。所以对于任意点,从根到这个点的路径上,轻边数量少于log(n)条(否则这棵树不止n个点)。相连的重边可以当成一根重链一起跳,从根到某点的路劲上,断开的重链必定不超过log(n)条,因为断开的重链之间必定由轻边链接,而轻边数量不超过log(n)。所以每次关于两点路径的查询/修改在树上的复杂度为log(n)级别,再乘上每次操作时数据结构(线段树/树状数组)的log(n),每次操作的实际复杂度为log(n)^2。

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define root 1,1,n
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N=1e5+4;
int n,m,O,P;
int head[N],etot;
struct Edge {
	int v,nxt;
}e[N<<1];
int siz[N],son[N],dep[N],fa[N];
int in[N],out[N],top[N],rk[N],tim;
int a[N],laz[N<<2],sum[N<<2];
inline int read() {
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f;
}
inline void adde(int u,int v) {
	e[++etot].nxt=head[u],e[etot].v=v,head[u]=etot;
}
inline void dfs1(int p,int f) {
	int mx=0;
	dep[p]=dep[fa[p]=f]+1,siz[p]=1;
	for (int i=head[p];~i;i=e[i].nxt) {
		int v=e[i].v;
		if (v^f) {
			dfs1(v,p);
			siz[p]+=siz[v];
			if (mx<siz[v]) {
				mx=siz[v];
				son[p]=v;
			}
		}
	}
}
inline void dfs2(int p,int tp) {
	rk[in[p]=++tim]=p,top[p]=tp;
	if (~son[p]) dfs2(son[p],tp);
	for (int i=head[p];~i;i=e[i].nxt) {
		int v=e[i].v;
		if (v^son[p]&&v^fa[p]) dfs2(v,v);
	}
	out[p]=tim;
}
inline void pushup(int rt) {
	sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%P;
}
inline void pushdown(int rt,int len) {
	if (laz[rt]) {
		(laz[rt<<1]+=laz[rt])%=P;
		(laz[rt<<1|1]+=laz[rt])%=P;
		(sum[rt<<1]+=(len-(len>>1))*laz[rt])%=P;
		(sum[rt<<1|1]+=(len>>1)*laz[rt])%=P;
		laz[rt]=0;
	}
}
inline void build(int rt,int l,int r) {
	if (l==r) {
		sum[rt]=a[rk[l]];
		return ;
	}
	int mid=l+r>>1;
	build(lson);
	build(rson);
	pushup(rt);
}
inline void modify(int rt,int l,int r,int L,int R,int val) {
	if (L<=l&&r<=R) {
		(sum[rt]+=(r-l+1)*val)%=P;
		(laz[rt]+=val)%=P;
		return ;
	}
	pushdown(rt,r-l+1);
	int mid=l+r>>1;
	if (L<=mid) modify(lson,L,R,val);
	if (mid<R) modify(rson,L,R,val);
	pushup(rt);
}
inline int query(int rt,int l,int r,int L,int R) {
	if (L<=l&&r<=R) return sum[rt];
	pushdown(rt,r-l+1);
	int mid=l+r>>1,ret=0;
	if (L<=mid) (ret+=query(lson,L,R))%=P;
	if (mid<R) (ret+=query(rson,L,R))%=P;
	return ret;
}
inline void add(int x,int y,int val) {
	int tx=top[x],ty=top[y];
	while (tx^ty) {
		if (dep[tx]<dep[ty]) {
			x^=y^=x^=y;
			tx^=ty^=tx^=ty;
		}
		modify(root,in[tx],in[x],val);
		x=fa[tx],tx=top[x];
	}
	if (dep[x]<dep[y]) x^=y^=x^=y;
	modify(root,in[y],in[x],val);
}
inline int ask(int x,int y) {
	int tx=top[x],ty=top[y],ret=0;
	while (tx^ty) {
		if (dep[tx]<dep[ty]) {
			x^=y^=x^=y;
			tx^=ty^=tx^=ty;
		}
		(ret+=query(root,in[tx],in[x]))%=P;
		x=fa[tx],tx=top[x];
	}
	if (dep[x]<dep[y]) x^=y^=x^=y;
	(ret+=query(root,in[y],in[x]))%=P;
	return ret;
}
int main() {
//	freopen("in1.txt","r",stdin);
	memset(head,-1,sizeof(head));
	memset(son,-1,sizeof(son));
	n=read(),m=read(),O=read(),P=read();
	for (register int i=1;i<=n;++i) a[i]=read()%P;
	for (register int i=1;i<n;++i) {
		int u=read(),v=read();
		adde(u,v);
		adde(v,u);
	}
	dfs1(O,0);
	dfs2(O,O);
	build(root);
	for (register int i=0;i<m;++i) {
		int opt=read();
		switch (opt) {
			case 1: {
				int x=read(),y=read(),z=read();
				add(x,y,z);
				break;
			}
			case 2: {
				int x=read(),y=read();
				printf("%d\n",ask(x,y));
				break;
			}
			case 3: {
				int x=read(),z=read();
				modify(root,in[x],out[x],z);
				break;
			}
			case 4: {
				int x=read();
				printf("%d\n",query(root,in[x],out[x]));
				break;
			}
		}
	}
	return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值