重链剖分模板
(求解dfs序的代码块应该放在第二个dfs里,即求重儿子的同时求dfs序,这样才能保证同一条链上的结点dfs序连续)
/**********
明天你是否会想起
昨天未调完的题
明天你是否还惦记
考场写挂的暴力
**********/
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int mod=1e18;//按题目要求随时修改.
void read(int &x){
int f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10%mod+(s-'0')%mod;s=getchar();}//改成了取模~~
x=x%mod*f;//改成了取模~
}
const int N=1e5+10;
struct xds
{
int l,r,sum;
int lazy;
}xd[4*N];
vector<int>f[N];
int n,m,root,p;
int fa[N],dep[N],sum[N],son[N],top[N];
int dfs_x[N],fid_x[N];///dfs_x-->给定树上的点在线段树里对应的序号,即dfs序
/// fid_x-->线段树里的序号对应给定树的序号.
int val[N];
int tot;
//俩遍dfs进行树剖
void dfs(int father,int cur)
{
sum[cur]=1;
for(auto v:f[cur])
{
if(v==father) continue;
dep[v]=dep[cur]+1;
fa[v]=cur;
dfs(cur,v);
sum[cur]+=sum[v];
if(sum[v]>sum[son[cur]]) son[cur]=v;
}
}
void dfs2(int fcur,int cur)
{
top[cur]=fcur;
tot++;
dfs_x[cur]=tot;//dfs序
fid_x[tot]=cur;//存一下dfs序对应的原先树的编号,方便后面线段树初始化值
if(son[cur]) dfs2(fcur,son[cur]);
for(auto v:f[cur])
{
if(v==fa[cur]||v==son[cur]) continue;
dfs2(v,v);
}
}
///线段树,带求和懒标记
void pushup(int u)
{
xd[u].sum=xd[u<<1].sum+xd[u<<1|1].sum;
}
void build(int u,int l,int r)
{
if(l==r)
{
// cout<<val[fid_x[l]]<<endl;
xd[u] = {l, r, val[fid_x[l]], 0};
}
else
{
int mid=l+r>>1;
xd[u]={l,r,0,0};
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
void pushdown(int u)
{
if(xd[u].lazy)
{
xd[u<<1].sum+=xd[u].lazy*(xd[u<<1].r-xd[u<<1].l+1);
xd[u<<1|1].sum+=xd[u].lazy*(xd[u<<1|1].r-xd[u<<1|1].l+1);
xd[u<<1].lazy+=xd[u].lazy;
xd[u<<1|1].lazy+=xd[u].lazy;
xd[u].lazy=0;
}
}
void motify(int u,int l,int r,int c)
{
if(xd[u].l>=l&&xd[u].r<=r)
{
xd[u].sum+=(xd[u].r-xd[u].l+1)*c;
xd[u].lazy+=c;
}
else
{
pushdown(u);
int mid=xd[u].l+xd[u].r>>1;
if(l<=mid) motify(u<<1,l,r,c);
if(r>mid) motify(u<<1|1,l,r,c);
pushup(u);
}
}
int query(int u,int l,int r)
{
if(xd[u].l>=l&&xd[u].r<=r) return xd[u].sum;
else
{
pushdown(u);
int mid=xd[u].l+xd[u].r>>1;
int res=0;
if(l<=mid) res=query(u<<1,l,r);
if(r>mid) res+=query(u<<1|1,l,r);
return res;
}
}//俩个操作,求和和修改路径上的值
void cli(int l,int r,int c)
{
while(top[l]!=top[r])
{
if(dep[top[l]]>dep[top[r]])
{
motify(1,dfs_x[top[l]],dfs_x[l],c);
l=fa[top[l]];
}
else
{
motify(1,dfs_x[top[r]],dfs_x[r],c);
r=fa[top[r]];
}
}
int l_2=min(dfs_x[l],dfs_x[r]);
int r_2=max(dfs_x[l],dfs_x[r]);
motify(1,l_2,r_2,c);
}
int cli2(int l,int r)
{
int res=0;
while(top[l]!=top[r])
{
if(dep[top[l]]>dep[top[r]])
{
res+=query(1,dfs_x[top[l]],dfs_x[l]);
l=fa[top[l]];
}
else
{
res+=query(1,dfs_x[top[r]],dfs_x[r]);
r=fa[top[r]];
}
}
int l_2=min(dfs_x[l],dfs_x[r]);
int r_2=max(dfs_x[l],dfs_x[r]);
res+=query(1,l_2,r_2);
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m>>root>>p;
for(int i=1;i<=n;i++)
{
cin>>val[i];
}
for(int i=0;i<n-1;i++)
{
int u,v;
cin>>u>>v;
f[u].push_back(v);
f[v].push_back(u);
}
dfs(0,root);
dfs2(root,root);
build(1,1,n);
while(m--)
{
int op,l,r,c;
cin>>op;
if(op==1)
{
cin>>l>>r>>c;
cli(l,r,c);
}
else if(op==2)
{
cin>>l>>r;
int ans=cli2(l,r);
cout<<ans%p<<endl;
}
else if(op==3)
{
cin>>l>>c;
motify(1,dfs_x[l],dfs_x[l]+sum[l]-1,c);//以l为根的子树的编号连续,且l的dfs序编号最小
}
else
{
cin>>l;
cout<<query(1,dfs_x[l],dfs_x[l]+sum[l]-1)%p<<endl;
}
}
return 0;
}