树剖学习地址:树链剖分详解(洛谷模板 P3384) - ChinHhh - 博客园
这次学只用了一个多小时,感觉还好,树剖也不是很难嘛~(就是代码超长
没什么好讲的,人家的详解已经说得比较清楚啦,就是重新按DFS序建一棵线段树,然后在树链上跳跳,再在线段树上搞搞就行了。
参考代码:
/*keep on going and never give up*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define db(x) cerr<<(#x)<<" "<<(x)<<" "<<endl;
#define endl "\n"
#define fast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double E = exp(1);
const double PI = acos(-1.0);
const int maxn=2e5+10;
struct qaq{
int l,r;
int sum,mul,add,cg;
}t[maxn<<1];
#define ls t[p<<1]
#define rs t[p<<1|1]
#define now t[p]
int n,m,a[maxn],mod,s;
struct SGTree{
void bd(int p,int l,int r){
now.l=l,now.r=r;
if(l==r){
t[p].sum=a[l];
return ;
}
int mid=l+r>>1;
bd(p<<1,l,mid);
bd(p<<1|1,mid+1,r);
now.sum=ls.sum+rs.sum;
}
//spread||pushdown 为线段树的关键,如何处理好各标记的更新成为解题的关键。
void spd(int p){
ls.sum+=((ls.r-ls.l+1)*now.add)%mod;
rs.sum+=((rs.r-rs.l+1)*now.add)%mod;
ls.add+=(ls.add*now.mul+now.add)%mod;
rs.add+=(rs.add*now.mul+now.add)%mod;
now.add=0;
}
void add(int p,int l,int r,int x){
if(now.l>=l&&now.r<=r){
now.add+=x; now.add%=mod;
now.sum+=x*(now.r-now.l+1); now.sum%=mod;
return ;
}
spd(p);
now.sum=ls.sum+rs.sum;
int mid=now.l+now.r>>1;
if(l<=mid) add(p<<1,l,r,x);
if(r>mid) add(p<<1|1,l,r,x);
now.sum=(ls.sum+rs.sum)%mod;
}
int ask(int p,int l,int r){
if(now.l>=l&&now.r<=r) return now.sum%mod;
spd(p);
int res=0;
int mid=now.l+now.r>>1;
if(l<=mid) res+=ask(p<<1,l,r);
if(r>mid) res+=ask(p<<1|1,l,r);
return res%mod;
}
}sg;
int son[maxn],id[maxn],fa[maxn],dep[maxn],siz[maxn],top[maxn],num,w[maxn];
struct node{
int to,nxt;
}e[maxn];int tot,head[maxn];
void add(int x,int y){ e[++tot]={y,head[x]};head[x]=tot;}
void dfs1(int x,int f){
dep[x]=dep[f]+1;
fa[x]=f;
siz[x]=1;
int mson=-1;
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(f==v) continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>mson) son[x]=v,mson=siz[v];
}
}
void dfs2(int x,int t){
id[x]=++num;
a[num]=w[x];
top[x]=t;
if(!son[x]) return ;
dfs2(son[x],t);
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int qrange(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
int res=sg.ask(1,id[top[x]],id[x]);
ans+=res;
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=sg.ask(1,id[x],id[y]);
return ans%mod;
}
void addrange(int x,int y,int k){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
sg.add(1,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
sg.add(1,id[x],id[y],k);
}
int qson(int x){
return sg.ask(1,id[x],id[x]+siz[x]-1)%mod;
}
void addson(int x,int k){
sg.add(1,id[x],id[x]+siz[x]-1,k);
}
signed main(){
fast
cin>>n>>m>>s>>mod;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<n;i++){
int x,y;cin>>x>>y;
add(x,y);add(y,x);
}
dfs1(s,0);
dfs2(s,s);
sg.bd(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y,z;cin>>op;
if(op==1){
cin>>x>>y>>z;
addrange(x,y,z);
}
else if(op==2){
cin>>x>>y;
cout<<qrange(x,y)<<endl;
}
else if(op==3){
cin>>x>>y;
addson(x,y);
}
else {
cin>>x;
cout<<qson(x)<<endl;
}
}
}
ps:找了好一会bug,发现是线段树上的标记改错了qaq