题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入输出格式
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
输入输出样例
输入样例#1: 复制
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
输出样例#1: 复制
2
21
说明
时空限制:1s,128M
n<=10^5 , m<=10^5。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 200005;
struct Edge{
int nxt,to;
}edge[MAXN];
struct Node{
int sum,lazy;
}node[MAXN*2];
int n,m,r,p,cnt,head[MAXN],w[MAXN],id[MAXN];
int d[MAXN],siz[MAXN],fa[MAXN],num;
int wt[MAXN],top[MAXN],res,son[MAXN];
inline void add(int bg,int ed){
edge[++cnt].to=ed;
edge[cnt].nxt=head[bg];
head[bg]=cnt;
}
inline void dfs1(int x,int f,int deep){
d[x]=deep;
fa[x]=f;
siz[x]=1;
int maxson=-1;
for(int i=head[x];i;i=edge[i].nxt){
int u=edge[i].to;
if(u==f) continue;
dfs1(u,x,deep+1);
siz[x]+=siz[u];
if(siz[u]>maxson) son[x]=u,maxson=siz[u];
}
}
inline void dfs2(int x,int topf){
id[x]=++num;
wt[num]=w[x];
top[x]=topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i=head[x];i;i=edge[i].nxt){
int u=edge[i].to;
if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
}
inline void pushdown(int rt,int len){
node[rt<<1].sum+=node[rt].lazy*(len-(len>>1));
node[rt<<1|1].sum+=node[rt].lazy*(len>>1);
node[rt<<1].sum%=p;
node[rt<<1|1].sum%=p;
node[rt<<1].lazy+=node[rt].lazy;
node[rt<<1|1].lazy+=node[rt].lazy;
node[rt].lazy=0;
}
inline void build(int rt,int l,int r){
if(l==r){
node[rt].sum=wt[l];
if(node[rt].sum>p)
node[rt].sum%=p;
return;
}
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
node[rt].sum=(node[rt<<1].sum+node[rt<<1|1].sum)%p;
}
inline void update(int rt,int l,int r,int L,int R,int k){
if(L<=l && r<=R){
node[rt].sum+=(r-l+1)*k;
node[rt].lazy+=k;
return;
}
int mid=((l+r)>>1);
if(node[rt].lazy) pushdown(rt,r-l+1);
if(L<=mid) update(rt<<1,l,mid,L,R,k);
if(R>mid) update(rt<<1|1,mid+1,r,L,R,k);
node[rt].sum=(node[rt<<1].sum+node[rt<<1|1].sum)%p;
}
inline void query(int rt,int l,int r,int L,int R){
if(L<=l && r<=R){
res+=node[rt].sum;
res%=p;
return;
}
int mid=(l+r)/2;
if(node[rt].lazy) pushdown(rt,r-l+1);
if(L<=mid) query(rt<<1,l,mid,L,R);
if(R>mid) query(rt<<1|1,mid+1,r,L,R);
}
inline void updRange(int x,int y,int k){
k%=p;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(d[x]>d[y]) swap(x,y);
update(1,1,n,id[x],id[y],k);
}
inline int qRange(int x,int y) {
int ans=0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
res=0;
query(1,1,n,id[top[x]],id[x]);
ans+=res;
ans%=p;
x=fa[top[x]];
}
if(d[x]>d[y]) swap(x,y);
res=0;
query(1,1,n,id[x],id[y]);
ans+=res;
return ans%p;
}
inline void updSon(int x,int k){
update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
inline int qSon(int x){
res=0;
query(1,1,n,id[x],id[x]+siz[x]-1);
return res;
}
int main() {
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
while(m--){
int k,x,y,z;
scanf("%d",&k);
if(k==1){
scanf("%d%d%d",&x,&y,&z);
updRange(x,y,z);
}
else if(k==2){
scanf("%d%d",&x,&y);
printf("%d
",qRange(x,y));
}
else if(k==3){
scanf("%d%d",&x,&y);
updSon(x,y);
}
else{
scanf("%d",&x);
printf("%d
",qSon(x));
}
}
return 0;
}