青莲武者 @ 2024-08-16 13:55:17
#include<bits/stdc++.h>
using namespace std;
int n,m,r,P;
int p[200005],siz[200005],d[200005],son[200005],top[200005],id[200005],cnt,val[200005],f[200005];
vector<int> c[200005],tr[200005];
int L[800005],R[800005];
long long sum[800005],lazy[800005];
void build(int l, int r, int x){
L[x] = l, R[x] = r, lazy[x] = 0;
if (l == r) {
sum[x]=val[l]%P;
return;
}
int mid = (l + r) / 2;
build(l, mid, x * 2);
build(mid + 1, r, x * 2 + 1);
sum[x] = (sum[x*2]+sum[x*2+1])%P;
return;
}
int Len(int x){
return R[x] - L[x] + 1;
}
void pushdown(int x){
if (lazy[x]){
lazy[x * 2]=(lazy[x*2]+lazy[x])%P;
lazy[x * 2 + 1]=(lazy[x*2+1]+lazy[x])%P;
sum[x * 2]=(sum[x*2]+lazy[x] * Len(x * 2))%P;
sum[x * 2 + 1]=(sum[x*2+1]+lazy[x] * Len(x * 2+1))%P;
lazy[x] = 0;
}
return;
}
void update(int l, int r, int x, long long k){
if (l <= L[x] && R[x] <= r){
lazy[x]=(lazy[x]+k)%P;
sum[x]=(sum[x]+k *Len(x))%P;
return;
}
pushdown(x);
int mid = (L[x] + R[x]) / 2;
if (l <= mid) update(l, r, x * 2, k);
if (r > mid) update(l, r, x * 2 + 1, k);
sum[x] =(sum[x * 2] + sum[x * 2 + 1])%P;
}
long long query(int l, int r, int x){
if (l <= L[x] && R[x] <= r){
return sum[x];
}
pushdown(x);
long long ret = 0; int mid = (L[x] + R[x]) / 2;
if (l <= mid) ret += query(l, r, x * 2);
if (r > mid) ret += query(l, r, x * 2 + 1);
return ret%P;
}
void dfs1(int nowp,int dep){
siz[nowp]=1;
d[nowp]=dep;
for(int i=0;i<c[nowp].size();++i){
if(c[nowp][i]!=f[nowp]){
f[c[nowp][i]]=nowp;
dfs1(c[nowp][i],dep+1);
tr[nowp].push_back(c[nowp][i]);
siz[nowp]+=siz[c[nowp][i]];
if(siz[c[nowp][i]]>siz[son[nowp]]){
son[nowp]=c[nowp][i];
}
}
}
if(siz[nowp]==1) son[nowp]=-1;
}
void dfs2(int nowp,int topx){
id[nowp]=++cnt;
val[cnt]=p[nowp];
top[cnt]=topx;
if(son[nowp]==-1) return;
dfs2(son[nowp],topx);
for(int i=0;i<tr[nowp].size();++i){
if(tr[nowp][i]!=son[nowp]){
dfs2(tr[nowp][i],tr[nowp][i]);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>r>>P;
for(int i=1;i<=n;++i) cin>>p[i];
for(int i=1;i<n;++i){
int a,b;
cin>>a>>b;
c[a].push_back(b);
c[b].push_back(a);
}
f[r]=0;
dfs1(r,0);
dfs2(r,r);
build(1,n,1);
while(m--){
int op,x,y,z;
cin>>op;
if(op==1){
cin>>x>>y>>z;
while(top[id[x]]!=top[id[y]]){
if(d[top[id[x]]]<d[top[id[y]]]) swap(x,y);
update(id[top[id[x]]],id[x],1,z%P);
x=f[top[x]];
}
if(d[x]>d[y]) swap(x,y);
update(id[x],id[y],1,z%P);
}else if(op==2){
cin>>x>>y;
long long ret=0;
while(top[id[x]]!=top[id[y]]){
if(d[top[id[x]]]<d[top[id[y]]]) swap(x,y);
ret+=query(id[top[id[x]]],id[x],1);
x=f[top[id[x]]];
}
if(d[x]>d[y]) swap(x,y);
ret+=query(id[x],id[y],1);
cout<<ret%P<<'\n';
}else if(op==3){
cin>>x>>z;
update(id[x],id[x]+siz[id[x]]-1,1,z%P);
}else{
cin>>x;
cout<<query(id[x],id[x]+siz[id[x]]-1,1)%P<<'\n';
}
}
return 0;
}
by dyyzy @ 2024-08-16 14:07:50
感觉dfs2挂了,top[nowp]=topx;
by __cheng827922__ @ 2024-08-16 14:08:03
大家都是绿名 为什么你就是管理员
by dyyzy @ 2024-08-16 14:11:00
dfs2里面的判断除了不能等于重儿子以外还不能等于父亲
by dyyzy @ 2024-08-16 14:13:16
跳重链的时候不需要套一层id[],如104行
while(top[id[x]]!=top[id[y]]){
while(top[x]!=top[y]){
by clzzw666 @ 2024-08-16 14:13:53
@dyyzy 没有吧,dfs1中他是top[cnt]=topx;
by clzzw666 @ 2024-08-16 14:14:50
顺便带个数据1
输入
8 10 2 448348
458 718 447 857 633 264 238 944
1 2
2 3
3 4
6 2
1 5
5 7
8 6
3 7 611
4 6
3 1 267
3 2 111
1 6 3 153
3 7 673
4 8
2 6 1
4 7
3 4 228
输出
1208
1055
2346
1900
by dyyzy @ 2024-08-16 14:16:45
@clzzw666 cnt
不是记录dfn序的吗,dfs2预处理的是当前节点重链的顶
by liwanxian @ 2024-08-16 14:19:07
@cheng827922 ta不是管理员啊?
by clzzw666 @ 2024-08-16 14:19:27
@dyyzy 没错,但我想表达的是,我们的写法是top[当前节点]=father;
,所以跳重链的时候不需要套一层id[]
by clzzw666 @ 2024-08-16 14:19:50
但是他的写法不一样