#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200005;
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int n,m,rt,mod,a[N],b[N];
int head[N],nxt[N],to[N],_cnt;
int siz[N],fa[N],dep[N],son[N],tp[N],dfn[N],rnk[N],num;
void add(int x,int y) {
to[++_cnt]=y,nxt[_cnt]=head[x],head[x]=_cnt;
}
struct SegmentTree {
int sum,len,dat;
}t[N<<4];
void popup(int p) {
t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
}
void pushdown(int p) {
t[p*2].sum=(t[p*2].sum+t[p].dat*t[p*2].len%mod)%mod;
t[p*2+1].sum=(t[p*2+1].sum+t[p].dat*t[p*2+1].len%mod)%mod;
t[p*2].dat=(t[p*2].dat+t[p].dat)%mod;
t[p*2+1].dat=(t[p*2+1].dat+t[p].dat)%mod;
t[p].dat=0;
}
void build(int p,int l,int r) {
t[p].len=r-l+1;
if(l==r) {
t[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(p*2,l,mid); build(p*2+1,mid+1,r);
popup(p);
}
int query(int p,int l,int r,int ql,int qr) {
if(ql<=l&&r<=qr) return t[p].sum;
pushdown(p);
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=(ans+query(p*2,l,mid,ql,qr))%mod;
if(mid<qr) ans=(ans+query(p*2+1,mid+1,r,ql,qr))%mod;
return ans;
}
void update(int p,int l,int r,int ql,int qr,int x) {
if(ql<=l&&r<=qr) {
t[p].dat=(t[p].dat+x)%mod; t[p].sum=(t[p].sum+t[p].len*x%mod)%mod;
return;
}
pushdown(p);
int mid=(l+r)>>1;
if(ql<=mid) update(p*2,l,mid,ql,qr,x);
if(mid<qr) update(p*2+1,mid+1,r,ql,qr,x);
popup(p);
}
void dfs1(int x,int fath,int deep) {
dep[x]=deep,fa[x]=fath,siz[x]=1;
int maxson=-1;
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(y==fath) continue;
dfs1(y,x,deep+1);
siz[x]+=siz[y];
if(siz[y]>maxson) maxson=siz[y],son[x]=y;
}
}
void dfs2(int x,int topf) {
dfn[x]=++num,a[num]=b[x],tp[x]=topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(!dfn[y]) dfs2(y,y);
}
}
int querysum(int x,int y) {
int ans=0,fx=tp[x],fy=tp[y];
while(fx!=fy) {
if(dep[fx]>=dep[fy]) ans=(ans+query(1,1,n,dfn[fx],dfn[x])),x=fa[fx];
else ans=(ans+query(1,1,n,dfn[fy],dfn[y]))%mod,y=fa[fy];
fx=tp[x],fy=tp[y];
}
if(dfn[x]<dfn[y]) ans=(ans+query(1,1,n,dfn[x],dfn[y]))%mod;
else ans=(ans+query(1,1,n,dfn[y],dfn[x]))%mod;
return ans;
}
void queryadd(int x,int y,int z) {
int fx=tp[x],fy=tp[y];
while(fx!=fy) {
if(dep[fx]>=dep[fy]) update(1,1,n,dfn[fx],dfn[x],z),x=fa[fx];
else update(1,1,n,dfn[fy],dfn[y],z),y=fa[fy];
fx=tp[x],fy=tp[y];
}
if(dfn[x]<dfn[y]) update(1,1,n,dfn[x],dfn[y],z);
else update(1,1,n,dfn[y],dfn[x],z);
}
signed main() {
n=read(),m=read(),rt=read(),mod=read();
for(int i=1;i<=n;i++) b[i]=read()%mod;
for(int i=1;i<n;i++) {
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs1(rt,0,1); dfs2(rt,rt);
build(1,1,n);
for(int i=1;i<=m;i++) {
int type=read();
if(type==1) {
int x=read(),y=read(),z=read();
queryadd(x,y,z%mod);
}
else if(type==2) {
int x=read(),y=read();
printf("%lld\n",querysum(x,y));
}
else if(type==3) {
int x=read(),z=read();
update(1,1,n,dfn[x],dfn[x]+siz[x]-1,z%mod);
}
else if(type==4) {
int x=read();
printf("%lld\n",query(1,1,n,dfn[x],dfn[x]+siz[x]-1));
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」