传送门
题意:
给你一个有个顶点的树,树上的每一个点都有一个点权,现在有种操作:
- ,代表将结点到结点的最近的路径上的所有点的点权增加
- ,代表将结点到结点的最近的路径上的所有点的点权减少
- ,代表求出结点的点权。
题目分析:
树链剖分的模板题。
倘若只有操作和操作,则我们只需要用树上差分用的时间复杂度完成操作。
但是,现在这个问题中,因此操作的存在,使得用树上差分去做的话时间复杂度将会不优。
因此我们可以考虑采用树链剖分。
我们将树上的重链剖分出来之后,获取出他们的序,并用数据结构(线段树/树状数组)去维护区间的和即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=50005;
struct Node{
int to,next;
}q[100005];
struct ST{
int sum,len,lazy;
}tr[maxn<<2];
int head[maxn],cnt=0,tot=0,f[maxn],dis[maxn],son[maxn],size[maxn],top[maxn];
int id[maxn],rk[maxn],v[maxn];
void add_edge(int from,int to){
q[cnt].to=to;
q[cnt].next=head[from];
head[from]=cnt++;
}
void dfs1(int x){
size[x]=1,dis[x]=dis[f[x]]+1;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(to==f[x]) continue;
f[to]=x;
dfs1(to);
size[x]+=size[to];
if(size[to]>size[son[x]]){
son[x]=to;
}
}
}
void dfs2(int x,int t){
top[x]=t;
id[x]=++tot;
rk[tot]=x;
if(son[x]) dfs2(son[x],t);
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(to==son[x]||to==f[x]) continue;
dfs2(to,to);
}
}
void push_up(int rt){
tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
}
void push_down(int rt){
if(tr[rt].lazy){
tr[rt<<1].sum+=1ll*tr[rt].lazy*tr[rt<<1].len;
tr[rt<<1|1].sum+=1ll*tr[rt].lazy*tr[rt<<1|1].len;
tr[rt<<1].lazy=tr[rt<<1].lazy+tr[rt].lazy;
tr[rt<<1|1].lazy=tr[rt<<1|1].lazy+tr[rt].lazy;
tr[rt].lazy=0;
}
}
void build(int l,int r,int rt){
tr[rt].lazy=0;
tr[rt].len=r-l+1;
if(l==r){
tr[rt].sum=v[rk[l]];
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(rt);
}
void update(int L,int R,int l,int r,int rt,int k){
if(L<=l&&R>=r){
tr[rt].lazy=tr[rt].lazy+k;
tr[rt].sum=tr[rt].sum+tr[rt].len*k*1l;
return ;
}
push_down(rt);
int mid=(l+r)>>1;
if(L<=mid) update(L,R,l,mid,rt<<1,k);
if(R>mid) update(L,R,mid+1,r,rt<<1|1,k);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
return tr[rt].sum;
}
push_down(rt);
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=query(L,R,l,mid,rt<<1);
if(R>mid) res+=query(L,R,mid+1,r,rt<<1|1);
return res;
}
int cal(int x,int y){
int res=0;
while(top[x]!=top[y]){
if(dis[top[x]]<dis[top[y]]) swap(x,y);
res+=query(id[top[x]],id[x],1,tot,1);
x=f[top[x]];
}
if(id[x]>id[y]) swap(x,y);
res+=query(id[x],id[y],1,tot,1);
return res;
}
void UPDATE(int x,int y,int c){
while(top[x]!=top[y]){
if(dis[top[x]]<dis[top[y]]) swap(x,y);
update(id[top[x]],id[x],1,tot,1,c);
x=f[top[x]];
}
if(id[x]>id[y]) swap(x,y);
update(id[x],id[y],1,tot,1,c);
}
int main()
{
int n,m,t;
while(~scanf("%d%d%d",&n,&m,&t)){
memset(head,-1,sizeof(head));
memset(dis,0,sizeof(dis));
memset(son,0,sizeof(son));
tot=0;
cnt=0;
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
for(int i=1;i<n;i++){
int from,to;
scanf("%d%d",&from,&to);
add_edge(from,to);
add_edge(to,from);
}
dfs1(1);
dfs2(1,1);
build(1,tot,1);
while(t--){
int x,y,z;
char op[2];
scanf("%s",op);
if(op[0]=='I'){
scanf("%d%d%d",&x,&y,&z);
UPDATE(x,y,z);
}
if(op[0]=='D'){
scanf("%d%d%d",&x,&y,&z);
z=-z;
UPDATE(x,y,z);
}
if(op[0]=='Q'){
scanf("%d",&x);
int res=query(id[x],id[x],1,tot,1);
printf("%d
",res);
}
}
}
return 0;
}