题目描述
给你一棵具有N个点(编号为1到N)M条边的树,并给定各个点权的值,然后有3种操作:
- I C1 C2 K:把C1与C2的路径上的所有点权值加上K
- D C1 C2 K:把C1与C2的路径上的所有点权值减去K
- Q C:查询节点编号为C的权值
分析
树剖模版题,只不过用树状数组就可以了,不必写线段树。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N=50005;
struct Edge {
int to,next;
}e[N*2];
int n,m,p;
int cnt,h[N],v[N];
int dep[N],prt[N],size[N],son[N];
int seg[N],top[N],sum[N];
void addedge(int x,int y) {
e[++cnt]=(Edge){y,h[x]};
h[x]=cnt;
}
void Dfs1(int x,int fa) {
dep[x]=dep[fa]+1;
size[x]=1;
for (int i=h[x];i;i=e[i].next) {
int y=e[i].to;
if (y==fa) continue;
prt[y]=x;
Dfs1(y,x);
size[x]+=size[y];
if (size[son[x]]<size[y]) son[x]=y;
}
}
void Dfs2(int x,int tp) {
seg[x]=++seg[0];
top[x]=tp;
if (son[x]) Dfs2(son[x],top[x]);
for (int i=h[x];i;i=e[i].next) {
int y=e[i].to;
if (top[y]) continue;
Dfs2(y,y);
}
}
int Ask(int x) {
int ret=0;
while (x) {
ret+=sum[x];
x-=lowbit(x);
}
return ret;
}
void update(int x,int y) {
while (x<=seg[0]) {
sum[x]+=y;
x+=lowbit(x);
}
}
void UpRange(int x,int y,int z) {
int fx=top[x],fy=top[y];
while (fx!=fy) {
if (dep[fx]<dep[fy]) {
swap(x,y);
swap(fx,fy);
}
update(seg[fx],z);
update(seg[x]+1,-z);
x=prt[fx];
fx=top[x];
}
if (dep[x]>dep[y]) swap(x,y);
update(seg[x],z);
update(seg[y]+1,-z);
}
int main() {
while (~scanf("%d%d%d",&n,&m,&p)) {
memset(sum,0,sizeof sum);
memset(h,0,sizeof h);
cnt=0;
for (int i=1;i<=n;i++) scanf("%d",&v[i]);
for (int i=1;i<=m;i++) {
int a,b;
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
Dfs1(1,1);
Dfs2(1,1);
for (int i=1;i<=n;i++) {
update(seg[i],v[i]);
update(seg[i]+1,-v[i]);
}
for (int i=1;i<=p;i++) {
char ch[10];
int x,y,z;
scanf("%s%d",ch,&x);
if (ch[0]=='I') {
scanf("%d%d",&y,&z);
UpRange(x,y,z);
} else if (ch[0]=='D') {
scanf("%d%d",&y,&z);
UpRange(x,y,-z);
} else {
printf("%d\n",Ask(seg[x]));
}
}
}
return 0;
}