分清楚inseg,intr数组的含义;
如果区间在一条链上,直接在线段树上修改可;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll MAXN=500005;
ll fst[MAXN<<1],nxt[MAXN<<1],inseg[MAXN],top[MAXN],intr[MAXN];
ll fa[MAXN],deep[MAXN],size[MAXN],son[MAXN],a[MAXN];
ll num,n,m,r,p,tot;
struct hh {ll f,t;}ma[MAXN<<2];
struct sh {ll delta,l,r,sum;}tree[MAXN<<2];
void dfs1(ll x,ll f)
{
deep[x]=deep[f]+1;
fa[x]=f,size[x]=1;
for(ll i=fst[x];i;i=nxt[i])
{
ll u=ma[i].t;
if(u==f) continue;
dfs1(u,x);
size[x]+=size[u];
if(!son[x] || size[son[x]]<size[u]) son[x]=u;
}
return;
}
void dfs2(ll x,ll st)
{
inseg[x]=++num;
top[x]=st;
intr[num]=x;
if(!son[x]) return;
dfs2(son[x],st);
for(ll i=fst[x];i;i=nxt[i])
{
ll u=ma[i].t;
if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
return;
}
void build(ll f,ll t)
{
ma[++tot]=(hh){f,t};
nxt[tot]=fst[f];
fst[f]=tot;
return;
}
void up(ll now)
{
tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
return;
}
void build_tree(ll now,ll l,ll r)
{
tree[now].l=l;
tree[now].r=r;
ll mid=(l+r)>>1;
if(l==r)
{
tree[now].sum=a[intr[l]];
return;
}
build_tree(now<<1,l,mid);
build_tree(now<<1|1,mid+1,r);
up(now);
return;
}
void pushdown(ll now)
{
if(tree[now].delta)
{
tree[now<<1].sum+=((tree[now<<1].r-tree[now<<1].l+1)*tree[now].delta)%p;
tree[now<<1|1].sum+=((tree[now<<1|1].r-tree[now<<1|1].l+1)*tree[now].delta)%p;
tree[now<<1].delta+=tree[now].delta;
tree[now<<1|1].delta+=tree[now].delta;
tree[now].delta=0;
}
return;
}
ll query(ll now,ll l,ll r)
{
ll ans=0;
if(l<=tree[now].l && r>=tree[now].r) return tree[now].sum%p;
ll mid=(tree[now].l+tree[now].r)>>1;
pushdown(now);
if(l<=mid) ans+=query(now<<1,l,r);
if(r>=mid+1) ans+=query(now<<1|1,l,r);
return ans%p;
}
void cha(ll now,ll l,ll r,ll v)
{
if(l<=tree[now].l && tree[now].r<=r)
{
tree[now].sum+=((tree[now].r-tree[now].l+1)*v)%p;
tree[now].delta+=v;
return;
}
pushdown(now);
ll mid=(tree[now].r+tree[now].l)>>1;
if(l<=mid) cha(now<<1,l,r,v);
if(r>=mid+1) cha(now<<1|1,l,r,v);
up(now);
return;
}
ll find_sum(ll x,ll y)
{
ll fx=top[x],fy=top[y],ans=0;
while(fx!=fy)
{
if(deep[fx]<deep[fy]) swap(fx,fy),swap(x,y);
ans+=query(1,inseg[fx],inseg[x]);
x=fa[fx],fx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
ans+=(query(1,inseg[x],inseg[y]))%p;
return ans%p;
}
void find_cha(ll x,ll y,ll v)
{
ll fx=top[x],fy=top[y];
while(fx!=fy)
{
if(deep[fx]<deep[fy]) swap(fx,fy),swap(x,y);
cha(1,inseg[fx],inseg[x],v);
x=fa[fx],fx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
cha(1,inseg[x],inseg[y],v);
return;
}
void solve()
{
cin>>n>>m>>r>>p;
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<n;i++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
build(x,y),build(y,x);
}
dfs1(r,r),dfs2(r,r);
build_tree(1,1,n);
for(ll i=1;i<=m;i++)
{
ll f,x,y,z;
scanf("%lld",&f);
if(f==1)
{
scanf("%lld%lld%lld",&x,&y,&z);
find_cha(x,y,z);
}
else if(f==2)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",find_sum(x,y)%p);
}
else if(f==3)
{
scanf("%lld%lld",&x,&z);
cha(1,inseg[x],inseg[x]+size[x]-1,z);
}
else
{
scanf("%lld",&x);
printf("%lld\n",query(1,inseg[x],inseg[x]+size[x]-1)%p);
}
}
return;
}
int main()
{
solve();
return 0;
}