萌新刚学OI $10^{-9} ms$,求调树链剖分板子
  • 板块学术版
  • 楼主SnowTrace
  • 当前回复2
  • 已保存回复2
  • 发布时间2022/12/15 21:52
  • 上次更新2023/10/24 07:35:29
查看原帖
萌新刚学OI $10^{-9} ms$,求调树链剖分板子
580036
SnowTrace楼主2022/12/15 21:52
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>p[200005];
int vis[200005],dfn[200005],top[200005],size[200005],son[200005],d[200005],f[200005],a[200005],r[200005],b[200005];
int n,m,rr,mod,nw =0;
struct node{
	int l,r,sum =0;
	int lazy = 0;
	void add(int x){
		lazy+=x,lazy%=mod,sum= (sum+(r-l)*x)%mod;
		return;
	}
}tree[400005];
//---------------------------
void push_down(int k){
	tree[k<<1].add(tree[k].lazy),tree[k<<1|1].add(tree[k].lazy);
	tree[k].lazy = 0;
}void build(int l,int r,int k){
	tree[k].l = l,tree[k].r = r;
	if(l+1 == r){
	//	cout<<l<<' '<<b[l]<<endl;
		tree[k].sum = b[l];return;
	}build(l,l+r>>1,k<<1),build(l+r>>1,r,k<<1|1);
	tree[k].sum = (tree[k<<1].sum+tree[k<<1|1].sum)%mod;
	return;
}void upd(int l,int r,int k,int ad){
	int ll = tree[k].l,rr =tree[k].r;
	if(ll>=r or rr<=l)return;
	if(l<=ll and rr<=r){
		tree[k].add(ad);return;
	}push_down(k);
	upd(l,r,k<<1,ad),upd(l,r,k<<1|1,ad);
	tree[k].sum = (tree[k<<1].sum+tree[k<<1|1].sum)%mod;
	return;
}int query(int l,int r,int k){
//	cout<<l <<' '<<r<< ' '<<tree[k].l <<' '<<tree[k].r <<' '<<k<<' '<<tree[k].sum<<endl;
	int ll = tree[k].l,rr = tree[k].r;
	if(ll>=r or l>=rr)return 0;
	if(l<=ll and rr<=r){
		return tree[k].sum;
	}push_down(k);
	return (query(l,r,k<<1)+query(l,r,k<<1|1))%mod;
}
//---------------------------
void dfs1(int now,int fa){
	dfn[now] = ++nw,size[now] = 1,d[now] = d[fa]+1,f[now] = fa;
	int mx =0;
	for(int i=0;i<p[now].size();i++){
		if(p[now][i]!=fa){
			dfs1(p[now][i],now);
			size[now]+=size[p[now][i]];
			if(mx<size[p[now][i]]){
				mx =size[p[now][i]],son[now] = p[now][i];
			}
		}
	}return;
}void dfs2(int now,int fa,int ok){
	dfn[now] = ++nw;
	if(ok)top[now] = top[fa];
	r[now] = dfn[now];
	for(int i=0;i<p[now].size();i++){
		if(p[now][i] == son[now])dfs2(p[now][i],now,1),r[now] = max(r[now],r[p[now][i]]);
	}for(int i =0;i<p[now].size();i++){
		if(p[now][i]!=son[now] and p[now][i]!=fa)dfs2(p[now][i],now,0),r[now] = max(r[now],r[p[now][i]]);
	}return;
}void upd1(int x,int y,int add){
	while(top[x]!=top[y]){
		if(d[top[x]]<d[top[y]])swap(x,y);
		upd(dfn[top[x]],dfn[x]+1,1,add);
		x = f[top[x]];
	}if(d[x]<d[y])swap(x,y);
	upd(dfn[y],dfn[x]+1,1,add);
}int query1(int x,int y){
	int res =0;
	while(top[x]!=top[y]){
		if(d[top[x]]<d[top[y]])swap(x,y);
		res = (res+query(dfn[top[x]],dfn[x]+1,1))%mod;
		x = f[top[x]];
	}if(d[x]<d[y])swap(x,y);
	res+=query(dfn[y],dfn[x]+1,1);
	return res;
}void upd2(int x,int add){
	int xx= query(dfn[x],r[x]+1,1);
	//cout << dfn[x] << " " << r[x]+1 <<" " << xx << endl;
	upd(dfn[x],r[x]+1,1,add);
//	cout<<query(3,4,1)<<endl;
}int query2(int x){
	int xx=  query(dfn[x],r[x]+1,1);
	//cout << dfn[x] << " " << r[x]+1 <<" " << xx << endl;
	//cout<<query(3,4,1)<<endl;
	return query(dfn[x],r[x]+1,1);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n >> m >> rr >> mod;
	for(int i=1;i<=n;i++)cin >> a[i];
	for(int i=1;i<n;i++){
		int a,b;cin >> a >> b;
		p[a].push_back(b),p[b].push_back(a);	
	}dfs1(rr,rr);
	memset(dfn,-1,sizeof(dfn));
	for(int i=1;i<=n;i++)top[i] = i;
	nw = 0;
	dfs2(rr,rr,0);
	for(int i=1;i<=n;i++){
		b[dfn[i]] = a[i];
	}//for(int i=1;i<=n;i++)cout << b[i] << " ";
	//cout << endl;
	build(1,n+1,1);
	//cout<<query(3,4,1)<<endl;
	while(m--){
		int s;
		cin >> s;
		if(s == 1){
			int a,b,c;cin>> a >> b >> c;
			upd1(a,b,c);
		}if(s == 2){
			int a,b;cin >> a>> b;
			cout << query1(a,b) << '\n';
		}if(s == 3){
			int x,y;cin>> x >> y;
			upd2(x,y);
		}if(s == 4){
			int x;cin>> x;
			cout << query2(x) << '\n';
		}
	}return 0;
}
  • 1 x y z,表示将树从 xxyy 结点最短路径上所有节点的值都加上 zz

  • 2 x y,表示求树从 xxyy 结点最短路径上所有节点的值之和。

  • 3 x z,表示将以 xx 为根节点的子树内所有节点值都加上 zz

  • 4 x 表示求以 xx 为根节点的子树内所有节点值之和

2022/12/15 21:52
加载中...