題目描述
如題,已知一棵包含 NN 個結點的樹(連通且無環),每個節點上包含一個數值,需要支持以下操作:
操作 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 之間連有一條邊(保證無環且連通)。
接下來 MM 行每行包含若干個正整數,每行表示一個操作,格式如下:
操作 1:1 x y z;
操作 2: 2 x y;
操作 3:3 x z;
操作 4: 4 x。
輸出格式
輸出包含若干行,分別依次表示每個操作2 或操作 4 所得的結果(對 P 取模)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx=1e5+10;
const int MAXN=2*1e6+10;
const double PI=cos(-1.0);
int dep[mx],top[mx],w[mx],son[mx],id[mx],siz[mx],fa[mx],res=0,cnt=0,a[mx];
int qr[mx<<2],laz[mx<<2];
int n,m,r,p;
vector<int>G[mx];
#define Temp template<typename T>
inline char nc()
{
static char buf[MAXN],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
char c=nc();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
while(c>='0'&&c<='9'){x=x*10+c-'0',c=nc();}
return x*f;
}
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)
inline void pushdown(int rt,int lenn)
{
laz[rt<<1]+=laz[rt];
laz[rt<<1|1]+=laz[rt];
qr[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
qr[rt<<1|1]+=laz[rt]*(lenn>>1);
qr[rt<<1]%=p;
qr[rt<<1|1]%=p;
laz[rt]=0;
}
inline void build(int rt,int l,int r)
{
if(l==r)
{
qr[rt]=w[l];
if(qr[rt]>p) qr[rt]%=p;
return ;
}
build(lson);
build(rson);
qr[rt]=(qr[rt<<1]+qr[rt<<1|1])%p;
}
inline void query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){res+=qr[rt];res%=p;return;}
else{
if(laz[rt])pushdown(rt,len);
if(L<=mid)query(lson,L,R);
if(R>mid)query(rson,L,R);
}
}
inline void updata(int rt,int l,int r,int L,int R,int k)
{
if(L<=l&&r<=R)
{
laz[rt]+=k;
qr[rt]+=k*len;
}
else{
if(laz[rt]) pushdown(rt,len);
if(L<=mid) updata(lson,L,R,k);
if(R>mid) updata(rson,L,R,k);
qr[rt]=(qr[rt<<1]+qr[rt<<1|1])%p;
}
}
inline int qrange(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=0;
query(1,1,n,id[top[x]],id[x]);
ans=(ans+res)%p;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);res=0;
query(1,1,n,id[x],id[y]);
ans+=res;
return ans%p;
}
inline int upqrange(int x,int y,int k)
{
k%=p;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
updata(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
updata(1,1,n,id[x],id[y],k);
}
inline void dfs(int u,int fath,int deep)
{
fa[u]=fath;
dep[u]=deep;
siz[u]=1;
int maxone=-1;
for(int i=0;i<G[u].size();i++)
{
int to=G[u][i];
if(to==fath) continue;
dfs(to,u,deep+1);
siz[u]+=siz[to];
if(siz[to]>maxone)
{
maxone=siz[to];
son[u]=to;
}
}
}
inline void dfs2(int x,int fst)
{
top[x]=fst;
id[x]=++cnt;
w[cnt]=a[x];
if(!son[x]) return;
dfs2(son[x],fst);
for(register int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&r,&p);
// n=read(),m=read(),r=read(),p=read();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
// x=read();y=read();
G[x].push_back(y);
G[y].push_back(x);
}
dfs(r,0,1);
dfs2(r,r);
build(1,1,n);
for(int i=1,x,y,z,q;i<=m;i++)
{
scanf("%d",&q);
if(q==1)
{
scanf("%d%d%d",&x,&y,&z);
// x=read();y=read();z=read();
upqrange(x,y,z);
}
else if(q==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",qrange(x,y));
}
else if(q==3)
{
scanf("%d%d",&x,&z);
// x=read();z=read();
updata(1,1,n,id[x],id[x]+siz[x]-1,z);
}
else
{
scanf("%d",&x);
res=0;query(1,1,n,id[x],id[x]+siz[x]-1);
printf("%d\n",res);
}
}
return 0;
}