树剖大法好!!!!!!
#include<bits/stdc++.h>
#define maxn 500005
using namespace std;
struct edge
{
int pre,to;
}e[maxn*2];
int n,m,root,mod,a[maxn],b[maxn],head[maxn],cnt=0,fa[maxn],dep[maxn],son[maxn],size[maxn],top[maxn],id[maxn];
int ndnum=0,lson[maxn],rson[maxn],sum[maxn],L,R,add[maxn];
void add_edge(int x,int y)
{
e[++cnt].pre=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs1(int x,int father,int depth)
{
int ans=-1;
size[x]=1;
dep[x]=depth;
fa[x]=father;
for(int i=head[x];i;i=e[i].pre)
{
int v=e[i].to;
if(v==father) continue;
dfs1(v,x,depth+1);
size[x]+=size[v];
if(size[v]>ans)
ans=size[v],son[x]=v;
}
}
void dfs2(int x,int topf)
{
id[x]=++cnt;
a[cnt]=b[x];
top[x]=topf;
if(son[x]==0) return;
dfs2(son[x],topf);
for(int i=head[x];i;i=e[i].pre)
{
int v=e[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
}
//树剖;
void down(int t,int l,int r)
{
if(add[t]!=0)
{
int mid=(l+r)>>1;
sum[lson[t]]+=(mid-l+1)*add[t];
sum[lson[t]]%=mod;
sum[rson[t]]+=(r-mid)*add[t];
sum[rson[t]]%=mod;
add[lson[t]]+=add[t];
add[rson[t]]+=add[t];
add[t]=0;
}
}
void build(int &t,int l,int r)
{
t=++ndnum;
if(l==r)
{
sum[t]=a[l];
return;
}
int mid=(l+r)>>1;
build(lson[t],l,mid);
build(rson[t],mid+1,r);
sum[t]=sum[lson[t]]+sum[rson[t]];
}
void modify(int t,int l,int r,int val)
{
if(l>=L&&r<=R)
{
sum[t]+=(r-l+1)*val;
add[t]+=val;
return;
}
down(t,l,r);
int mid=(l+r)>>1;
if(mid>=L) modify(lson[t],l,mid,val);
if(mid<R) modify(rson[t],mid+1,r,val);
sum[t]=sum[lson[t]]+sum[rson[t]];
}
int query(int t,int l,int r)
{
int ans=0;
if(l>=L&&r<=R)
return sum[t];
down(t,l,r);
int mid=(l+r)>>1;
if(L<=mid)
ans+=query(lson[t],l,mid);
if(R>mid)
ans+=query(rson[t],mid+1,r);
return ans%mod;
}
//线段树;
void modify_edge(int x,int y,int val)//x到top[x]中的节点在线段树上是连续的
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
L=id[top[x]];R=id[x];modify(1,1,n,val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
L=id[x];R=id[y];modify(1,1,n,val);
}
int query_edge(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
L=id[top[x]];R=id[x];ans=(ans+query(1,1,n))%mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
L=id[x];R=id[y];ans=(ans+query(1,1,n))%mod;
return ans%mod;
}
void modify_tree(int x,int val)//以i为根的子树的树在线段树上的编号为[i,i+子树节点数-1]
{
L=id[x];R=id[x]+size[x]-1;
modify(1,1,n,val);
}
int query_tree(int x)
{
L=id[x];R=id[x]+size[x]-1;
return query(1,1,n)%mod;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&root,&mod);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
dfs1(root,0,1);
cnt=0;
dfs2(root,root);
int R=0;
build(R,1,n);
for(int i=1;i<=m;i++)
{
int op,x,y,z;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&z);
modify_edge(x,y,z);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",query_edge(x,y));
}
else if(op==3)
{
scanf("%d%d",&x,&z);
modify_tree(x,z);
}
else
{
scanf("%d",&x);
printf("%d\n",query_tree(x));
}
}
return 0;
}
/*
5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
*/