贴一个觉得写的不错的链接:https://www.cnblogs.com/ivanovcraft/p/9019090.html
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=100010;
typedef long long ll;
using namespace std;
struct edge{
int v,nex;
}e[maxn<<1];
int fa[maxn],dep[maxn],fp[maxn],top[maxn],son[maxn],sz[maxn];
int head[maxn],tot,n,m,a[maxn],mod,root,p[maxn],cnt;
ll sum[maxn<<2],laz[maxn<<2];
int read(){
int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
void add(int u,int v) {
e[tot].v=v; e[tot].nex=head[u];
head[u]=tot++;
}
void dfs1(int u) {
sz[u]=1,son[u]=0;
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
if(sz[v]>sz[son[u]])son[u]=v;
sz[u]+=sz[v];
}
}
}
void dfs2(int u,int tp) {
p[u]=++cnt;
fp[p[u]]=u;
top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=son[u]&&v!=fa[u])dfs2(v,v);
}
}
void deal(int l,int r,int rt,ll v){
laz[rt]+=v,sum[rt]+=(ll)(r-l+1)*v;
}
void push_up(int rt){
sum[rt]=sum[lson]+sum[rson];
}
void build(int l,int r,int rt){
if (l==r){
sum[rt]=a[fp[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void push_down(int l,int r,int rt){
if(laz[rt]){
int mid=(l+r)/2;
deal(l,mid,lson,laz[rt]);
deal(mid+1,r,rson,laz[rt]);
laz[rt]=0;
}
}
void update(int ql,int qr,int l,int r,int rt,ll v){
if (l>=ql&&r<=qr){
deal(l,r,rt,v);
return;
}
push_down(l,r,rt);
int mid=(l+r)/2;
if(mid>=ql) update(ql,qr,l,mid,lson,v);
if(mid<qr) update(ql,qr,mid+1,r,rson,v);
push_up(rt);
}
void change(int x,int y,ll v){
int fx=top[x],fy=top[y];
while (fx!=fy){
if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
update(p[fx],p[x],1,n,1,v);
x=fa[fx],fx=top[x];
}
if (dep[x]>dep[y]) swap(x,y);
update(p[x],p[y],1,n,1,v);
}
ll query(int ql,int qr,int l,int r,int rt){
if (l>=ql&&r<=qr) {
return sum[rt];
}
push_down(l,r,rt);
ll now=0;
int mid=(l+r)/2;
if(mid>=ql) now=(now+query(ql,qr,l,mid,lson))%mod;
if(mid<qr) now=(now+query(ql,qr,mid+1,r,rson))%mod;
return now;
}
ll fin(int x,int y){
ll now=0;
int fx=top[x],fy=top[y];
while (fx!=fy){
if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
now+=query(p[fx],p[x],1,n,1),now%=mod;
x=fa[fx],fx=top[x];
}
if (dep[x]>dep[y]) swap(x,y);
now=(now+query(p[x],p[y],1,n,1))%mod;
return now;
}
int main(){
int x,y,op;
memset(head,-1,sizeof(head));
n=read(),m=read(),root=read(),mod=read();
rep(i,1,n) a[i]=read();
rep(i,1,n-1) x=read(),y=read(),add(x,y),add(y,x);
dfs1(root);
dfs2(root,root);
build(1,n,1);
ll w;
while (m--){
op=read(),x=read();
if(op==1){
y=read();
scanf("%lld",&w);
change(x,y,w);
}
else if(op==2){
y=read();
printf("%lld\n",fin(x,y));
}
else if(op==3){
scanf("%lld",&w);
update(p[x],p[x]+sz[x]-1,1,n,1,w);
}
else{
printf("%lld\n",(query(p[x],p[x]+sz[x]-1,1,n,1))%mod);
}
}
return 0;
}
终于把这个坑填上了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50010;
struct edge {
int v,nex;
} e[maxn<<1];
int head[maxn],tot;
int dep[maxn],p[maxn],fp[maxn],fa[maxn],top[maxn],son[maxn],siz[maxn];
//p为dfs序,top为当前节点的重链顶端,fp是当前结点在树状数组中的位置
int cnt;
int num[maxn];
void Add(int u,int v) {
e[tot].v=v;
e[tot].nex=head[u];
head[u]=tot++;
}
void dfs(int u) {
siz[u]=1,son[u]=0;
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
if(siz[v]>siz[son[u]])son[u]=v;
siz[u]+=siz[v];
}
}
}
void build(int u,int tp) {
p[u]=++cnt;
fp[p[u]]=u;
top[u]=tp;
if(son[u])build(son[u],tp);
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=son[u]&&v!=fa[u])build(v,v);
}
}
//树状数组
int arr[maxn];
inline int lowbit(int x){return x&(-x);}
inline int query(int x) {
int res=0;
while(x)res+=arr[x],x-=lowbit(x);
return res;
}
inline void add(int x,int n) {
while(x<maxn)arr[x]+=n,x+=lowbit(x);
}
inline int update(int x,int y,int n) {
add(x,n);
add(y+1,-n);
}
void change(int a,int b,int x) {
int f1=top[a],f2=top[b],tmp=0;
while(f1!=f2) {
if(dep[f1]<dep[f2])swap(f1,f2),swap(a,b);
update(p[f1],p[a],x);
a=fa[f1],f1=top[a];
}
// if(a==b)return;
if(dep[a]>dep[b])swap(a,b);
update(p[a],p[b],x);
}
int n,m,q,a,b,c;
char op[10];
int main() {
int T;
//freopen("f.txt","r",stdin);
while(~scanf("%d%d%d",&n,&m,&q)) {
memset(head,-1,sizeof(head));
memset(arr,0,sizeof(arr));
cnt=tot=0;
for(int i=1; i<=n; i++)scanf("%d",&num[i]);
for(int i=0; i<m; i++) {
scanf("%d%d",&a,&b);
Add(a,b);
Add(b,a);
}
dfs(1);
build(1,1);
for(int i=1;i<=n;i++)update(p[i],p[i],num[i]);
while(q--) {
scanf("%s",op);
if(op[0]=='Q') {
scanf("%d",&a);
printf("%d\n",query(p[a]));
} else {
scanf("%d%d%d",&a,&b,&c);
if(op[0]=='D')c=-c;
change(a,b,c);
}
}
}
return 0;
}
以下板子
题目描述
如题,已知一棵包含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为根节点的子树内所有节点值之和
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=100010;
typedef long long ll;
using namespace std;
struct edge{
int v,nex;
}e[maxn<<1];
int fa[maxn],dep[maxn],fp[maxn],top[maxn],son[maxn],sz[maxn];
int head[maxn],tot,n,m,a[maxn],mod,root,p[maxn],cnt;
ll sum[maxn<<2],laz[maxn<<2];
int read(){
int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
void add(int u,int v) {
e[tot].v=v; e[tot].nex=head[u];
head[u]=tot++;
}
void dfs1(int u) {
sz[u]=1,son[u]=0;
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
if(sz[v]>sz[son[u]])son[u]=v;
sz[u]+=sz[v];
}
}
}
void dfs2(int u,int tp) {
p[u]=++cnt;
fp[p[u]]=u;
top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int i=head[u]; ~i; i=e[i].nex) {
int v=e[i].v;
if(v!=son[u]&&v!=fa[u])dfs2(v,v);
}
}
void deal(int l,int r,int rt,ll v){
laz[rt]+=v,sum[rt]+=(ll)(r-l+1)*v;
}
void push_up(int rt){
sum[rt]=sum[lson]+sum[rson];
}
void build(int l,int r,int rt){
if (l==r){
sum[rt]=a[fp[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void push_down(int l,int r,int rt){
if(laz[rt]){
int mid=(l+r)/2;
deal(l,mid,lson,laz[rt]);
deal(mid+1,r,rson,laz[rt]);
laz[rt]=0;
}
}
void update(int ql,int qr,int l,int r,int rt,ll v){
if (l>=ql&&r<=qr){
deal(l,r,rt,v);
return;
}
push_down(l,r,rt);
int mid=(l+r)/2;
if(mid>=ql) update(ql,qr,l,mid,lson,v);
if(mid<qr) update(ql,qr,mid+1,r,rson,v);
push_up(rt);
}
void change(int x,int y,ll v){
int fx=top[x],fy=top[y];
while (fx!=fy){
if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
update(p[fx],p[x],1,n,1,v);
x=fa[fx],fx=top[x];
}
if (dep[x]>dep[y]) swap(x,y);
update(p[x],p[y],1,n,1,v);
}
ll query(int ql,int qr,int l,int r,int rt){
if (l>=ql&&r<=qr) {
return sum[rt];
}
push_down(l,r,rt);
ll now=0;
int mid=(l+r)/2;
if(mid>=ql) now=(now+query(ql,qr,l,mid,lson))%mod;
if(mid<qr) now=(now+query(ql,qr,mid+1,r,rson))%mod;
return now;
}
ll fin(int x,int y){
ll now=0;
int fx=top[x],fy=top[y];
while (fx!=fy){
if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
now+=query(p[fx],p[x],1,n,1),now%=mod;
x=fa[fx],fx=top[x];
}
if (dep[x]>dep[y]) swap(x,y);
now=(now+query(p[x],p[y],1,n,1))%mod;
return now;
}
int main(){
int x,y,op;
memset(head,-1,sizeof(head));
n=read(),m=read(),root=read(),mod=read();
rep(i,1,n) a[i]=read();
rep(i,1,n-1) x=read(),y=read(),add(x,y),add(y,x);
dfs1(root);
dfs2(root,root);
build(1,n,1);
ll w;
while (m--){
op=read(),x=read();
if(op==1){
y=read();
scanf("%lld",&w);
change(x,y,w);
}
else if(op==2){
y=read();
printf("%lld\n",fin(x,y));
}
else if(op==3){
scanf("%lld",&w);
update(p[x],p[x]+sz[x]-1,1,n,1,w);
}
else{
printf("%lld\n",(query(p[x],p[x]+sz[x]-1,1,n,1))%mod);
}
}
return 0;
}