luogu3384 模板树链剖分

Posted poorpool

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3384 模板树链剖分相关的知识,希望对你有一定的参考价值。

强烈推荐这篇文章,一下子就看懂AC了。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
struct Edge{
	int too, nxt;
}edge[200005];
int n, m, r, p, uu, vv, ww, tt, w[100005], hea[100005], ecnt, dep[100005];
int fa[100005], siz[100005], son[100005], idx[100005], cnt, wt[100005];
int top[100005];
void add_edge(int fro, int too){
	edge[++ecnt].nxt = hea[fro];
	edge[ecnt].too = too;
	hea[fro] = ecnt;
}
void dfs1(int x, int f){
	dep[x] = dep[f] + 1;
	fa[x] = f;
	siz[x] = 1;
	int maxSon=-1;
	for(int i=hea[x]; i; i=edge[i].nxt){
		int t=edge[i].too;
		if(t==f)	continue;
		dfs1(t, x);
		siz[x] += siz[t];
		if(siz[t]>maxSon){
			son[x] = t;
			maxSon = siz[t];
		}
	}
}
void dfs2(int x, int topf){
	idx[x] = ++cnt;
	wt[cnt] = w[x] % p;
	top[x] = topf;
	if(!son[x])	return ;
	dfs2(son[x], topf);
	for(int i=hea[x]; i; i=edge[i].nxt){
		int t=edge[i].too;
		if(t==fa[x] || t==son[x])	continue;
		dfs2(t, t);
	}
}
struct SFT{
	int sum[400005];
	int tag[400005];
	void build(int o, int l, int r){
		if(l==r)	sum[o] = wt[l];
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			if(l<=mid)	build(lson, l, mid);
			if(mid<r)	build(rson, mid+1, r);
			sum[o] = (sum[lson] + sum[rson]) % p;
		}
	}
	void pushdown(int o, int l, int r, int lson, int rson, int mid){
		tag[lson] = (tag[lson] + tag[o]) % p;
		tag[rson] = (tag[rson] + tag[o]) % p;
		sum[lson] = (sum[lson] + (mid-l+1) * tag[o] % p) % p;
		sum[rson] = (sum[rson] + (r-mid) * tag[o] % p) % p;
		tag[o] = 0;
	}
	void update(int o, int l, int r, int x, int y, int k){
		if(l>=x && r<=y){
			sum[o] = (sum[o] + (r-l+1) * k % p) % p;
			tag[o] = (tag[o] + k) % p;
		}
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			if(tag[o])	pushdown(o, l, r, lson, rson, mid);
			if(x<=mid)	update(lson, l, mid, x, y, k);
			if(mid<y)	update(rson, mid+1, r, x, y, k);
			sum[o] = (sum[lson] + sum[rson]) % p;
		}
	}
	int query(int o, int l, int r, int x, int y){
		if(l>=x && r<=y)	return sum[o];
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			int ans=0;
			if(tag[o])	pushdown(o, l, r, lson, rson, mid);
			if(x<=mid)	ans = (ans + query(lson, l, mid, x, y)) % p;
			if(mid<y)	ans = (ans + query(rson, mid+1, r, x, y)) % p;
			return ans;
		}
	}
}sgt;
void updRange(int uu, int vv, int ww){
	ww %= p;
	while(top[uu]!=top[vv]){
		if(dep[top[uu]]<dep[top[vv]])	swap(uu, vv);
		sgt.update(1, 1, n, idx[top[uu]], idx[uu], ww);
		uu = fa[top[uu]];
	}
	if(dep[uu]>dep[vv])	swap(uu, vv);
	sgt.update(1, 1, n, idx[uu], idx[vv], ww);
}
int queryRange(int uu, int vv){
	int ans=0;
	while(top[uu]!=top[vv]){
		if(dep[top[uu]]<dep[top[vv]])	swap(uu, vv);
		ans = (ans + sgt.query(1, 1, n, idx[top[uu]], idx[uu])) % p;
		uu = fa[top[uu]];
	}
	if(dep[uu]>dep[vv])	swap(uu, vv);
	ans = (ans + sgt.query(1, 1, n, idx[uu], idx[vv])) % p;
	return ans;
}
int main(){
	cin>>n>>m>>r>>p;
	for(int i=1; i<=n; i++)
		scanf("%d", &w[i]);
	for(int i=1; i<n; i++){
		scanf("%d %d", &uu, &vv);
		add_edge(uu, vv);
		add_edge(vv, uu);
	}
	dep[r] = 1;
	dfs1(r, 0);
	dfs2(r, r);
	sgt.build(1, 1, n);
	while(m--){
		scanf("%d", &tt);
		if(tt==1){
			scanf("%d %d %d", &uu, &vv, &ww);
			updRange(uu, vv, ww);
		}
		else if(tt==2){
			scanf("%d %d", &uu, &vv);
			printf("%d\\n", queryRange(uu, vv));
		}
		else if(tt==3){
			scanf("%d %d", &uu, &ww);
			sgt.update(1, 1, n, idx[uu], idx[uu]+siz[uu]-1, ww);
		}
		else{
			scanf("%d", &uu);
			printf("%d\\n", sgt.query(1, 1, n, idx[uu], idx[uu]+siz[uu]-1));
		}
	}
	return 0;
}

以上是关于luogu3384 模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

luogu 3384 模板树链剖分

luogu3384 模板树链剖分

Luogu P3384树链剖分模板

[luogu P3384] [模板]树链剖分

Luogu P3384 模板树链剖分

luogu3384模板树链剖分