Description
已知一棵包含 \(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\) 为根节点的子树内所有节点值之和
Solution
复习一下模板
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 400005;
int val[N],tag[N];
void pushup(int p) {
val[p]=val[p*2]+val[p*2+1];
}
void pushdown(int p,int l,int r) {
if(tag[p]) {
val[p*2]+=tag[p]*((l+r)/2-l+1);
val[p*2+1]+=tag[p]*(r-(l+r)/2);
tag[p*2]+=tag[p];
tag[p*2+1]+=tag[p];
tag[p]=0;
}
}
void build(int p,int l,int r,int *src) {
if(l==r) val[p]=src[l];
else {
build(p*2,l,(l+r)/2,src);
build(p*2+1,(l+r)/2+1,r,src);
pushup(p);
}
}
void modify(int p,int l,int r,int ql,int qr,int key) {
if(l>qr || r<ql) return;
if(l>=ql && r<=qr) {
val[p]+=(r-l+1)*key;
tag[p]+=key;
}
else {
pushdown(p,l,r);
modify(p*2,l,(l+r)/2,ql,qr,key);
modify(p*2+1,(l+r)/2+1,r,ql,qr,key);
pushup(p);
}
}
int query(int p,int l,int r,int ql,int qr) {
if(l>qr || r<ql) return 0;
if(l>=ql && r<=qr) {
return val[p];
}
else {
pushdown(p,l,r);
return query(p*2,l,(l+r)/2,ql,qr)+query(p*2+1,(l+r)/2+1,r,ql,qr);
}
}
vector <int> g[N];
int top[N],wson[N],siz[N],dep[N],vis[N],tid[N],did[N],fin[N],fa[N],cnt=0;
void link(int p,int q) {
g[p].push_back(q);
g[q].push_back(p);
}
void dfs1(int p) {
vis[p]=siz[p]=1;
for(int q:g[p]) if(vis[q]==0) {
dep[q]=dep[p]+1;
fa[q]=p;
dfs1(q);
siz[p]+=siz[q];
if(siz[q]>siz[wson[p]]) wson[p]=q;
}
}
void dfs2(int p) {
did[p]=++cnt;
tid[cnt]=p;
vis[p]=1;
if(wson[p]) top[wson[p]]=top[p],dfs2(wson[p]);
for(int q:g[p]) if(vis[q]==0) {
top[q]=q;
dfs2(q);
}
fin[p]=cnt;
}
int n,m,r,mod,v[N],w[N];
void presolve() {
dep[r]=1;
dfs1(r);
memset(vis,0,sizeof vis);
top[r]=r;
dfs2(r);
}
void link_modify(int p,int q,int v) {
while(top[p]-top[q]) {
if(dep[top[p]]>dep[top[q]]) swap(p,q);
modify(1,1,n,did[top[q]],did[q],v);
q=fa[top[q]];
}
if(dep[p]>dep[q]) swap(p,q);
modify(1,1,n,did[p],did[q],v);
}
int link_query(int p,int q) {
int ans=0;
while(top[p]-top[q]) {
if(dep[top[p]]>dep[top[q]]) swap(p,q);
ans+=query(1,1,n,did[top[q]],did[q]);
q=fa[top[q]];
}
if(dep[p]>dep[q]) swap(p,q);
ans+=query(1,1,n,did[p],did[q]);
return ans;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m>>r>>mod;
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<n;i++) {
int t1,t2;
cin>>t1>>t2;
link(t1,t2);
}
presolve();
for(int i=1;i<=n;i++) w[did[i]]=v[i];
build(1,1,n,w);
for(int i=1;i<=m;i++) {
int t1,t2,t3,t4;
cin>>t1;
if(t1==1) {
cin>>t2>>t3>>t4;
link_modify(t2,t3,t4);
}
if(t1==2) {
cin>>t2>>t3;
cout<<link_query(t2,t3)%mod<<endl;
}
if(t1==3) {
cin>>t2>>t3;
modify(1,1,n,did[t2],fin[t2],t3);
}
if(t1==4) {
cin>>t2;
cout<<query(1,1,n,did[t2],fin[t2])%mod<<endl;
}
}
}