#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100009
#define lson(x) (((x)<<1)+0)
#define rson(x) (((x)<<1)+1)
#define len(l,r) ((r)-(l)+1)
struct edge{int to,nxt;}e[N];
struct node{int fa,dep,siz,son,top,dfn;}tr[N];
struct seg{int l,r,sum,tag;}st[8*N];
int n,m,u,v,z,op,rt,md,opt,cnt,a[N],w[N],head[N];
//树链剖分
void dfs1(int id,int fa,int dep)
{
int mxsn=0;
tr[id].fa=fa;tr[id].dep=dep;
tr[id].siz=1;tr[id].son=0;
for(int i=head[id];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa) continue;
dfs1(to,id,dep+1);
tr[id].siz+=tr[to].siz;
if(mxsn<tr[to].siz) mxsn=tr[to].siz,tr[id].son=to;
}
}
void dfs2(int id,int top)
{
tr[id].dfn=++cnt;tr[id].top=top;w[cnt]=a[id];
printf("编号%d的值为%d\n",cnt,w[cnt]);
if(tr[id].son) dfs2(tr[id].son,top);
for(int i=head[id];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==tr[id].fa||to==tr[id].son) continue;
dfs2(to,to);
}
}
//线段树
void build(int id,int l,int r)
{
st[id].l=l,st[id].r=r;
if(l==r){printf("%d is push %d\n",id,w[l]);st[id].sum=w[l];return;}
int mid=(l+r)>>1;
printf("%d %d %d\n",id,l,r);
build(lson(id),l,mid);
build(rson(id),mid+1,r);
st[id].sum=(st[lson(id)].sum+st[rson(id)].sum)%md;
}
void pushdown(int id)
{
st[lson(id)].sum+=st[id].tag*len(st[lson(id)].l,st[lson(id)].r);
st[rson(id)].sum+=st[id].tag*len(st[rson(id)].l,st[rson(id)].r);
st[lson(id)].tag=(st[lson(id)].tag+st[id].tag)%md;
st[rson(id)].tag=(st[rson(id)].tag+st[id].tag)%md;
st[lson(id)].sum%=md,st[rson(id)].sum%=md;
st[id].tag=0;
}
void add(int id,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
printf("%d>=%d %d<=%d 故直接加到%d\n",l,x,r,y,id);
st[id].tag=(st[id].tag+k)%md;
st[id].sum=(st[id].sum+k*len(st[id].l,st[id].r))%md;
return;
}
pushdown(id);
int mid=(l+r)>>1;
if(mid>=x) add(lson(id),l,mid,x,y,k);
if(mid+1<=y) add(rson(id),mid+1,r,x,y,k);
st[id].sum=(st[lson(id)].sum+st[rson(id)].sum)%md;
}
int query(int id,int l,int r,int x,int y)
{
int res=0,mid=(l+r)>>1;
if(l>=x&&r<=y) return st[id].sum;
pushdown(id);
if(mid>=x) res=(res+query(lson(id),l,mid,x,y))%md;
if(mid+1<=y) res=(res+query(rson(id),mid+1,r,x,y))%md;
return res;
}
//维护剖分
void upd(int x,int y,int k)
{
while(tr[x].top!=tr[y].top)
{
if(tr[tr[x].top].dep<tr[tr[y].top].dep) swap(x,y);
printf("x:%d top:%d y:%d\n",x,tr[x].top,y);
add(1,1,n,tr[tr[x].top].dfn,tr[x].dfn,k);
printf("已经加完\n");
x=tr[tr[x].top].fa;
printf("向上跳到%d\n",x);
}
if(tr[x].dep>tr[y].dep) swap(x,y);
add(1,1,n,tr[x].dfn,tr[y].dfn,k);
}
int calc(int x,int y)
{
int res=0;
while(tr[x].top!=tr[y].top)
{
if(tr[tr[x].top].dep<tr[tr[y].top].dep) swap(x,y);
printf("x:%d y:%d\n",x,y);
res=(res+query(1,1,n,tr[tr[x].top].dfn,tr[x].dfn))%md;
printf("已经查询完成\n");
x=tr[tr[x].top].fa;
printf("向上跳到%d\n",x);
}
if(tr[x].dep>tr[y].dep) swap(x,y);
printf("x:%d y:%d\n",x,y);
res=(res+query(1,1,n,tr[x].dfn,tr[y].dfn))%md;
printf("%d %d %d\n",tr[x].dfn,tr[y].dfn,res);
return res;
}
void check(int id)
{
//printf("第%d个 范围%d~%d 值域%d 懒标记%d\n",id,st[id].l,st[id].r,st[id].sum,st[id].tag);
if(st[lson(id)].l!=0) check(lson(id));
if(st[rson(id)].l!=0) check(rson(id));
}
signed main()
{
scanf("%lld%lld%lld%lld",&n,&m,&rt,&md);
memset(head,-1,sizeof(head));opt=cnt=0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]%=md;
for(int i=1;i<n;i++)
{
scanf("%lld%lld",&u,&v);
e[++opt]=(edge){v,head[u]};head[u]=opt;
e[++opt]=(edge){u,head[v]};head[v]=opt;
}
dfs1(rt,rt,1);dfs2(rt,rt);build(1,1,n);
check(1);
for(int i=1;i<=n;i++)
{
printf("%d:父节点%d 深度%d 字树大小%d 重儿子%d 编号%d 链顶端%d\n",i,tr[i].fa,tr[i].dep,tr[i].siz,tr[i].son,tr[i].dfn,tr[i].top);
}
for(int i=1;i<=m;i++)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld%lld%lld",&u,&v,&z);
upd(u,v,z%md);
}
if(op==2)
{
scanf("%lld%lld",&u,&v);
printf("%lld\n",calc(u,v));
}
if(op==3)
{
scanf("%lld%lld",&u,&z);
printf("增加从%d到%d\n",tr[u].dfn,tr[u].dfn+tr[u].siz-1);
add(1,1,n,tr[u].dfn,tr[u].dfn+tr[u].siz-1,z%md);
}
if(op==4)
{
scanf("%lld",&u);
printf("%lld\n",query(1,1,n,tr[u].dfn,tr[u].dfn+tr[u].siz-1));
}
check(1);
}
return 0;
}
太简单的算法,发学术版怕被diss,况且灌水区的大佬多,所有为什么会RE啊?