luoguP3384 【模板】轻重链剖分

1 篇文章 0 订阅

第一次没照着模板抄就写出了3.8k的树po(十分高兴)
可能我还要再补充一下树po的性质啊。。。例题之类的
线段树记得开4倍空间,不然你就开8倍(不过我好菜啊,我初三才会树po,某些神仙初三都2分钟干完fail树上dfs序建可持久化线段树优化dp。。。。光速逃)

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

int n,m,rt,p,dex,tot;
int h[MAXN],num[MAXN],dep[MAXN],sz[MAXN],ch[MAXN],f[MAXN],id[MAXN],ik[MAXN],rid[MAXN],tp[MAXN];
int sum[8* MAXN],lazy[8* MAXN];

struct node{
	int from,to,next;
}e[MAXN << 1];

void add(int x , int y){
	tot++;
	e[tot].from = x;
	e[tot].to = y;
	e[tot].next = h[x];
	h[x] = tot;
}

void init(){
	tot = dex = 0;
	memset(h , -1 , sizeof(h));
	memset(ch , -1 , sizeof(ch));
	cin>>n>>m>>rt>>p;
	tp[rt] = rt;
	for(int i = 1 ; i <= n ; i++)cin>>num[i];
	for(int i = 1 ; i < n ; i++){
		int x,y;cin>>x>>y;
		add(x , y);
		add(y , x);
	}
}

int dfs(int now , int fa){
	sz[now] = 1;
	dep[now] = dep[fa] + 1;
	f[now] = fa;
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		if(e[i].to == fa)continue;
		dfs(e[i].to , now);
		sz[now] += sz[e[i].to];
	}
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		if(e[i].to == fa)continue;
		ch[now] = (sz[ch[now]] < sz[e[i].to] ? e[i].to : ch[now]);	
	}
}

int dfs2(int now , int fa){
	dex++;
	id[now] = dex;
	ik[dex] = now;
	if(ch[now] != (-1)){
		tp[ch[now]] = tp[now];
		dfs2(ch[now] , now);
	}
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		if(e[i].to == fa)continue;
		if(e[i].to == ch[now])continue;
		tp[e[i].to] = e[i].to;
		dfs2(e[i].to , now);
	}
	rid[now] = dex;
}

//tp´¢´æÿ¸öµãËùÔÚµÄÖØÁ´ÉϵÄ×¶Ë½ÚµãÔ­À´µÄ±àºÅ

int build(int rt , int l , int r){
	if(l == r){sum[rt] = num[ik[l]];return 0;}
	int mid = (l + r) >> 1;
	build(rt << 1 , l , mid);
	build((rt << 1) | 1 , mid + 1 , r);
	sum[rt] = (sum[rt << 1] + sum[(rt << 1) | 1]) % p;
	return 0;
} 

int push_down(int rt , int l , int r){
	int mid = (l + r) >> 1;
	sum[rt << 1] = (sum[rt << 1] + lazy[rt] * (mid - l + 1)) % p;
	sum[(rt << 1) | 1] = (sum[(rt << 1) | 1] + lazy[rt] * (r - mid)) % p;
	lazy[rt << 1] = (lazy[rt << 1] + lazy[rt]) % p;
	lazy[(rt << 1) | 1] = (lazy[(rt << 1) | 1] + lazy[rt]) % p;
	lazy[rt] = 0;
}

int que(int rt , int l , int r , int x , int y){
	if(r < x || l > y)return 0;
	if(x <= l && r <= y)return sum[rt];
	push_down(rt , l , r);
	int mid = (l + r) >> 1 , zz = 0;
	zz = (zz + que(rt << 1 , l , mid , x , y)) % p;
	zz = (zz + que((rt << 1) | 1 , mid + 1 , r , x , y)) % p;
	return zz;
}

int cc(int rt , int l , int r , int x , int y , int k){
	if(r < x || l > y)return 0;
	if(x <= l && r <= y){
		sum[rt] = (sum[rt] + k * (r - l + 1)) % p;
		lazy[rt] = (lazy[rt] + k) % p;
		return 0;
	}
	push_down(rt , l , r);
	int mid = (l + r) >> 1;
	cc(rt << 1 , l , mid , x , y , k);
	cc((rt << 1) | 1 , mid + 1 , r , x , y , k);
	sum[rt] = (sum[rt << 1] + sum[(rt << 1) | 1]) % p;
	return 0;
}

int ycl(){
	dfs(rt , rt);
	dfs2(rt , rt);
	build(1 , 1 , n);
}

int add2(int x , int y , int k){//´Óx½ÚµãÓëy½ÚµãÒ»Ö±ÍùÉÏÌø£¬Ê¹µÃ 
	while(tp[x] != tp[y]){
		if(dep[tp[x]] < dep[tp[y]])swap(x , y);
		cc(1 , 1 , n , id[tp[x]] , id[x] , k);
		x = f[tp[x]];
	}
	if(id[x] > id[y])swap(x , y);
	cc(1 , 1 , n , id[x] , id[y] , k);
	return 0;
}

int que2(int x , int y){
	int zz = 0;
	while(tp[x] != tp[y]){
		if(dep[tp[x]] < dep[tp[y]])swap(x , y);
		zz = (zz + que(1 , 1 , n , id[tp[x]] , id[x])) % p;
		x = f[tp[x]];
	}
	if(id[x] > id[y])swap(x , y);
	zz = (zz + que(1 , 1 , n , id[x] , id[y])) % p;
	return zz;
}

void solve(){
	for(int i = 1 ; i <= m ; i++){
		int a,b,c,d;
		cin>>a;
		if(a == 1){
			cin>>b>>c>>d;
			add2(b , c , d);
		}
		if(a == 2){
			cin>>b>>c;
			cout<<que2(b , c)<<endl;
		}
		if(a == 3){
			cin>>b>>c;
			cc(1 , 1 , n , id[b] , rid[b] , c);
		}
		if(a == 4){
			cin>>b;
			cout<<que(1 , 1 , n , id[b] , rid[b])<<endl;
		}
	}
}

int main(){
	init();
	ycl();
	solve();
} 

重链有个性质,,,我记得好像是这么在链上乱跳,平均复杂度是 O ( l o g n ) O(logn) O(logn)
于是很多神奇操作就可以在上面搞了(SCOI2020D1T1)就是一个例子(我现在还不会大佬说的套路题)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值