Steve_xh @ 2023-12-30 23:28:52
rt
#include<bits/stdc++.h>
using namespace std;
struct EDGE{
int to,next;
}e[100005<<1|1];
int n,m,r,mod,cnt,head[100005],a[100005];
int dep[100005],sum[100005],f[100005];
int id[100005],top[100005],son[100005],seg[100005],segcnt=0;
inline void add_edge(int u,int v){
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void dfs1(int now,int fa){
f[now]=fa;
dep[now]=dep[fa]+1;
sum[now]=1;
for(int i=head[now];i;i=e[i].next){
if(e[i].to==fa)
continue;
dfs1(e[i].to,now);
sum[now]+=sum[e[i].to];
if(sum[son[now]]<sum[e[i].to])
son[now]=e[i].to;
}
}
void dfs2(int now,int t){
top[now]=t;
seg[id[now]=++segcnt]=now;
if(!son[now])
return;
dfs2(son[now],t);
for(int i=head[now];i;i=e[i].next)
if(e[i].to!=f[now]&&e[i].to!=son[now])
dfs2(e[i].to,e[i].to);
}
struct TREE{
int l,r,v;
}t[100005<<2|1];
inline void pushup(int x){
t[x].v=(t[x<<1].v+t[x<<1|1].v)%mod;
}
void bt(int l,int r,int x){
t[x].l=l,t[x].r=r;
if(l==r){
t[x].v=a[seg[l]];
return;
}
int mid=(l+r)>>1;
bt(l,mid,x<<1);
bt(mid+1,r,x<<1|1);
pushup(x);
}
int query(int l,int r,int x){
if(l<=t[x].l&&t[x].r<=r)
return t[x].v;
int mid=(t[x].l+t[x].r)>>1,ans=0;
if(l<=mid)
ans=(ans+query(l,r,x<<1))%mod;
if(mid<r)
ans=(ans+query(l,r,x<<1|1))%mod;
return ans;
}
void upd(int l,int r,int x,int w){
if(l<=t[x].l&&t[x].r<=r)
return (void)(t[x].v=(t[x].v+w)%mod);
int mid=(t[x].l+t[x].r)>>1;
if(l<=mid)
upd(l,r,x<<1,w);
if(mid<r)
upd(l,r,x<<1|1,w);
pushup(x);
}
void op1(int x,int y,int z){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
if(top[x]==top[y])
return (void)upd(min(id[x],id[y]),max(id[x],id[y]),1,z);
upd(id[top[x]],id[x],1,z);
op1(f[top[x]],y,z);
}
int op2(int x,int y){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
if(top[x]==top[y])
return query(min(id[x],id[y]),max(id[x],id[y]),1);
return (query(id[top[x]],id[x],1)+op2(f[top[x]],y))%mod;
}
inline void op3(int x,int z){
upd(id[x],id[x]+sum[x]-1,1,z);
}
inline int op4(int x){
return query(id[x],id[x]+sum[x]-1,1);
}
int main(){
scanf("%d%d%d%d",&n,&m,&r,&mod);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),add_edge(u,v),add_edge(v,u);
dfs1(r,r);
dfs2(r,r);
bt(1,segcnt,1);
for(int i=1,op,x,y,z;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&x,&y,&z);
op1(x,y,z);
}else if(op==2){
scanf("%d%d",&x,&y);
printf("%d\n",op2(x,y));
}else if(op==3){
scanf("%d%d",&x,&z);
op3(x,z);
}else{
scanf("%d",&x);
printf("%d\n",op4(x));
}
}
return 0;
}
by Zzzcr @ 2023-12-30 23:34:17
区间加我怎么都没看到lazytag
by Steve_xh @ 2023-12-30 23:36:32
@Zzzcr 一定要么,我怎么见我也没t
by Zzzcr @ 2023-12-30 23:37:56
@Steve_xh 问题是 这么做是错的,建议重修线段树
by Steve_xh @ 2023-12-30 23:40:03
@Zzzcr 为啥会错,按理来说和正常是一样的吧
by Zzzcr @ 2023-12-30 23:44:27
@Steve_xh 当然不一样啦,假设更新一个线段树节点,后来查询它的子节点,这个子节点没有被更新到哇
by Steve_xh @ 2023-12-30 23:49:49
@Zzzcr 不太懂QwQ不应该先更新子节点然后再pushup嘛
by Steve_xh @ 2023-12-30 23:51:43
@Zzzcr 哦哦我明白了,如果一个区间刚好在lr范围他就加了v完事走人了QwQ