过了样例但0分
#include <iostream>
using namespace std;
int n,m,r,p;
const int kMaxN=1e5+1;
struct SLPF//树链
{
int heavyson;//这个节点的重儿子
int size,top,newid;//它的子树的大小,这条链的顶部,它的编号(线段树要用)
int father,deep;//它的父亲和深度
}s[kMaxN*2];
int num;
struct XDS//线段树
{
int l,r;//它所包括的区间
int val,add;//它的值和懒标记
}tr[kMaxN*4];
int a[kMaxN];
struct EDGE//存边不用解释
{
int to,nt;
}e[kMaxN*2];
int cnt,hd[kMaxN];
int zhi[kMaxN];
void Add(int a,int b)
{
e[++cnt].to=b;
e[cnt].nt=hd[a];
hd[a]=cnt;
}
void Build(int where,int l,int r)//建线段树
{
tr[where].l=l;
tr[where].r=r;
if(l==r)
{
tr[where].val=zhi[l]%p;
return;
}
int mid=(l+r)/2;
Build(where*2,l,mid);
Build(where*2+1,mid+1,r);
tr[where].val=(tr[where*2].val,tr[where*2+1].val)%p;
}
void Solve(int where)//处理懒标记
{
tr[where*2+1].val+=tr[where].add*(tr[where*2+1].l-tr[where*2+1].r+1)%p;
tr[where*2+1].val%=p;
tr[where*2].val+=tr[where].add*(tr[where*2].l-tr[where*2].r+1)%p;
tr[where].val%=p;
tr[where*2+1].add+=tr[where].add;
tr[where*2+1].add%=p;
tr[where*2].add+=tr[where].add;
tr[where*2].add%=p;
tr[where].add=0;
}
void Update(int where,int l,int r,int z)//线段树的区间更改
{
if(tr[where].l>=l&&tr[where].r<=r)
{
tr[where].val+=(z*(tr[where].l-tr[where].r+1)%p)%p;
tr[where].val%=p;
tr[where].add+=z%p;
tr[where].add%=p;
return;
}
Solve(where);
int mid=(tr[where].l+tr[where].r)/2;
if(mid>=l)
{
Update(where*2,l,r,z);
}
if(mid<r)
{
Update(where*2+1,l,r,z);
}
tr[where].val=tr[where*2+1].val+tr[where*2].val;
tr[where].val%=p;
}
int GetSum(int where,int l,int r)//线段树的区间查询
{
if(tr[where].l>=l&&tr[where].r<=r)
{
return tr[where].val;
}
Solve(where);
int mid=(tr[where].l+tr[where].r)/2,sum=0;
if(mid>=l)
{
sum+=GetSum(where*2,l,r);
sum%=p;
}
if(mid<r)
{
sum+=GetSum(where*2+1,l,r);
sum%=p;
}
return sum;
}
void dfs1(int now,int last)
{
s[now].deep=s[last].deep+1;//算深度
s[now].father=last;//算父亲
s[now].size=1;//算子树大小
int howmany=0;
for(int i=hd[now];i;i=e[i].nt)
{
if(e[i].to==last)continue;
dfs1(e[i].to,now);
s[now].size+=s[e[i].to].size;
if(howmany<s[e[i].to].size)//算重儿子
{
howmany=s[e[i].to].size;
s[now].heavyson=e[i].to;
}
}
}
void dfs2(int now,int top)
{
num++;
s[now].top=top;//算顶部
s[now].newid=num;//算编号
zhi[num]=a[now];//点的初始值赋值上来,建线段树要用
if(s[now].heavyson==0)return;
dfs2(s[now].heavyson,top);//搜重儿子
for(int i=hd[now];i;i=e[i].nt)
{
if(e[i].to==s[now].father||e[i].to==s[now].heavyson)continue;
dfs2(e[i].to,e[i].to);//轻儿子开一条新的链
}
}
void Change(int x,int y,int z)//树链更改(op=1)
{
while(s[x].top!=s[y].top)//不在同一条链上
{
if(s[s[x].top].deep<s[s[y].top].deep)
{
swap(x,y);
}
Update(1,s[s[x].top].newid,s[x].newid,z);
x=s[s[x].top].father;//跳出这一条链
}
if(s[x].deep>s[y].deep)
{
swap(x,y);
}
Update(1,s[x].newid,s[y].newid,z);
}
int GetAns(int x,int y)//同理(op=2)
{
int ans=0;
while(s[x].top!=s[y].top)
{
if(s[s[x].top].deep<s[s[y].top].deep)
{
swap(x,y);
}
ans+=GetSum(1,s[s[x].top].newid,s[x].newid);
ans%=p;
x=s[s[x].top].father;
}
if(s[x].deep>s[y].deep)
{
swap(x,y);
}
ans+=GetSum(1,s[x].newid,s[y].newid);
ans%=p;
return ans;
}
void Change2(int x,int z)//op=3
{
Update(1,s[x].newid,s[x].newid+s[x].size-1,z);
}
int GetAns2(int x)//op=4
{
return GetSum(1,s[x].newid,s[x].newid+s[x].size-1);
}
signed main()
{
cin>>n>>m>>r>>p;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
Add(a,b);
Add(b,a);
}
dfs1(r,0);
dfs2(r,r);
Build(1,1,n);
for(int i=1;i<=m;i++)
{
int op;
cin>>op;
if(op==1)
{
int x,y,z;
cin>>x>>y>>z;
Change(x,y,z);
}
else if(op==2)
{
int x,y;
cin>>x>>y;
cout<<GetAns(x,y)%p<<"\n";
}
else if(op==3)
{
int x,z;
cin>>x>>z;
Change2(x,z);
}
else if(op==4)
{
int x;
cin>>x;
cout<<GetAns2(x)%p<<"\n";
}
}
return 0;
}