第一次没照着模板抄就写出了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)就是一个例子(我现在还不会大佬说的套路题)