R_aier @ 2023-07-24 22:13:09
#include <bits/stdc++.h>
#define LOCAL
#define INPUTFILE "1.in"
#define OUTPUTFILE "1.out"
using namespace std;
const int maxn = 2e6 + 10;
struct edge
{
int to,next;
edge():next(-1){}
edge(int to,int next):to(to),next(next){}
}e[maxn*2];
int son[maxn],top[maxn],siz[maxn],fa[maxn],dep[maxn],v[maxn],tim,cnt,head[maxn];
int id[maxn],w[maxn],tree[maxn*4],tag[maxn*4];
int n,m,mod,root;
void addedge(int u,int v)
{
e[++cnt]=edge(v,head[u]);head[u]=cnt;
}
void dfs1(int u,int f)
{
dep[u]=dep[f]+1;fa[u]=f;siz[u]=1;
int maxsiz=-1;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v==f)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>maxsiz)
{
son[u]=v;maxsiz=siz[v];
}
}
}
void dfs2(int u,int t)
{
top[u]=t;id[u]=++tim;w[tim]=v[u];
if(!son[u])return;
dfs2(son[u],t);
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[u]&&v!=son[u])
dfs2(v,v);
}
}
void addtag(int l,int r,int p,int k)
{
tree[p]+=(r-l+1)*k;
tree[p]%=mod;
tag[p]+=k;
}
void push_up(int p)
{
tree[p]=tree[p*2]+tree[p*2+1];
tree[p]%=mod;
}
void push_down(int l,int r,int p)
{
if(!tag[p]) return;
int mid=(l+r)/2;
addtag(l,mid,p*2,tag[p]);
addtag(mid+1,r,p*2+1,tag[p]);
tag[p]=0;
}
void build(int l,int r,int p)
{
if(l==r){
tree[p]=w[l];
return;
}
int mid=(l+r)/2;
build(l,mid,p*2);
build(mid+1,r,p*2+1);
push_up(p);
tree[p]%=mod;
}
//l~r add k
void qupdate(int l,int r,int x,int y,int p,int k)
{
if (x >= l && y <= r)
{
addtag(x, y, p, k);
return;
}
push_down(x,y,p);
int mid = (x + y) / 2;
if (l <= mid)
qupdate(l, r, x, mid, p * 2, k);
if (r > mid)
qupdate(l, r, mid + 1, r, p * 2 + 1, k);
push_up(p);
}
int qquery(int l,int r,int x,int y,int p)
{
if (x >= l && y <= r)
{
return tree[p]%mod;
}
push_down(x,y,p);
int mid=(x+y)/2;
int res=0;
if (l <= mid)
res+=qquery(l, r, x, mid, p * 2);
if (r > mid)
res+=qquery(l, r, mid + 1, r, p * 2 + 1);
return res%mod;
}
void tupdate(int u,int v,int k)
{
while (top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
qupdate(id[top[u]],id[u],1,n,1,k);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
qupdate(id[u],id[v],1,n,1,k);
}
int tquery(int u,int v)
{
int res=0;
while (top[u]!=top[v])
{
if (dep[top[u]] < dep[top[v]])
swap(u, v);
res+=qquery(id[top[u]], id[u], 1, n, 1);
res%=mod;
u = fa[top[u]];
}
if (dep[u] > dep[v])
swap(u, v);
return (qquery(id[u], id[v], 1, n, 1)+res)%mod;
}
void zupdete(int r,int k)
{
qupdate(id[r],id[r]+siz[r]-1,1,n,1,k);
}
int zquery(int r)
{
return (qquery(id[r],id[r]+siz[r]-1,1,n,1)%mod);
}
int main()
{
clock_t clockf = clock();
#ifdef LOCAL
freopen(INPUTFILE, "r", stdin);
freopen(OUTPUTFILE, "w", stdout);
#endif
//=======================================================================================================================
cin>>n>>m>>root>>mod;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);addedge(v,u);
}
dfs1(root,root);
dfs2(root,root);
build(1,n,1);
int opt,x,y,z;
while (m--)
{
scanf("%d",&opt);
switch (opt)
{
case 1:{
scanf("%d%d%d",&x,&y,&z);
tupdate(x,y,z);
}
break;
case 2:{
scanf("%d%d",&x,&y);
printf("%d\n",tquery(x,y));
}
break;
case 3:{
scanf("%d%d",&x,&z);
zupdete(x,z);
}
break;
case 4:{
scanf("%d",&x);
printf("%d\n",zquery(x));
}
break;
}
}
//=======================================================================================================================
end:
cerr << "Time Used:" << clock() - clockf << "ms" << endl;
return 0;
}