题目描述
如题,已知一棵包含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
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=100000,M<=100000
(其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233)
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxx=100010;
int be[maxx],ne[maxx*2],to[maxx*2],e=0;
int fa[maxx],son[maxx],deep[maxx],size[maxx],jump[maxx],tot=0;
int x[maxx],y[maxx],a[maxx];
long long tree[maxx*4],lazy[maxx*4],val;
int n,q,root,mod;
void add(int x,int y){
to[++e]=y;
ne[e]=be[x];
be[x]=e;
}
int read(){
char x;
while((x=getchar())<'0' || x>'9');
int u=x-'0';
while((x=getchar())>='0' && x<='9')u=u*10+x-'0';
return u;
}
int dfs1(int id){
size[id]=1;
for(int i=be[id];i;i=ne[i]){
int go=to[i];
if(fa[id]==go)continue;
fa[go]=id;
deep[go]=deep[id]+1;
size[id]+=dfs1(go);
if(!son[id] || size[go]>size[son[id]])
son[id]=go;
}
return size[id];
}
void dfs2(int id,int top){
x[id]=++tot;
y[tot]=id;
jump[id]=top;
if(son[id]) dfs2(son[id],top);
for(int i=be[id];i;i=ne[i]){
int go=to[i];
if(fa[id]==go ||son[id]==go)continue;
dfs2(go,go);
}
}
void build(int id,int l,int r){
if(l==r){
tree[id]=a[y[l]]%mod;
// if(l==4) printf("%d~%d\n",y[l],id);
return ;
}
int mid=(l+r)>>1;
build(id<<1,l,mid),build(id<<1|1,mid+1,r);
tree[id]=(tree[id*2]+tree[id*2+1])%mod;
}
void update(int l,int r,int xl,int xr,int id,int v){
if(l>=xl && r<=xr) lazy[id]+=v;
else{
int mid=(l+r)>>1;
if(xl>mid)update(mid+1,r,xl,xr,id<<1|1,v);
else if(xr<=mid)update(l,mid,xl,xr,id<<1,v);
else update(l,mid,xl,mid,id<<1,v),update(mid+1,r,mid+1,xr,id<<1|1,v);
}
if(l<r)tree[id]=(tree[id<<1]+tree[id<<1|1])%mod;
if(l==r)tree[id]+=v;
else tree[id]=(tree[id]+lazy[id]*(r-l+1))%mod;
}
void pushdown(int id,int l,int r,int mid){
lazy[id<<1]=(lazy[id<<1]+lazy[id])%mod;
lazy[id<<1|1]=(lazy[id<<1|1]+lazy[id])%mod;
tree[id<<1]=(tree[id<<1]+(mid-l+1)*lazy[id])%mod;
tree[id<<1|1]=(tree[id<<1|1]+(r-mid)*lazy[id])%mod;
lazy[id]=0;
}
long long query(int l,int r,int cl,int cr,int id){
if(l>=cl && r<=cr){
return tree[id]%mod;
}
else{
int mid=(l+r)>>1;
if(lazy[id])pushdown(id,l,r,mid);
if(cl>mid) return query(mid+1,r,cl,cr,id<<1|1)%mod;
else if(cr<=mid) return query(l,mid,cl,cr,id<<1)%mod;
else return (query(l,mid,cl,mid,id<<1)+query(mid+1,r,mid+1,cr,id<<1|1))%mod;
}
}
void change(int a,int b,int w){
while(jump[a]!=jump[b]){
if(deep[jump[a]]>deep[jump[b]]){a^=b;b^=a;a^=b;}
update(1,tot,x[jump[b]],x[b],1,w);
// printf("%d~%d\n",x[jump[b]],x[b]);
b=fa[jump[b]];
}
if(deep[a]>deep[b]){a^=b;b^=a;a^=b;}
update(1,tot,x[a],x[b],1,w);
// printf("%d~%d\n",x[jump[b]],x[b]);
}
void ask(int a,int b){
while(jump[a]!=jump[b]){
if(deep[jump[a]]>deep[jump[b]]){a^=b;b^=a;a^=b;}
val=(val+query(1,tot,x[jump[b]],x[b],1))%mod;
b=fa[jump[b]];
}
if(deep[a]>deep[b]){a^=b;b^=a;a^=b;}
val=(val+query(1,tot,x[a],x[b],1))%mod;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int i,j,k;
n=read();
q=read();
root=read();
mod=read();
for(i=1;i<=n;i++){a[i]=read();a[i]%=mod;}
for(i=1;i<n;i++){
j=read();
k=read();
add(j,k);
add(k,j);
}
fa[root]=root;
dfs1(root);
dfs2(root,root);
build(1,1,tot);
// for(i=1;i<=n;i++)
// printf("%d~%d\n",3,query(1,tot,x[3],x[3],1,0));
while(q--){
int dog=read();
// printf("-------%d---------\n",dog);
if(dog==1){
i=read();
j=read();
val=read();
val%=mod;
change(i,j,val);
}
else if(dog==3){
i=read();
val=read();
val%=mod;
update(1,tot,x[i],x[i]+size[i]-1,1,val);
}
else if(dog==2){
i=read();
j=read();
val=0;
ask(i,j);
printf("%d\n",val%mod);
}
else{
i=read();
// printf("%d\n",x[i]);
printf("%d\n",query(1,tot,x[i],x[i]+size[i]-1,1)%mod);
}
// printf("-------%d---------\n",q);
// for(i=1;i<=n;i++) printf("%d~%d\n",i,query(1,tot,x[i],x[i],1,0));
}
return 0;
}