Description
小A走到一个山脚下,准备给自己造一个小屋。这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到
山顶放了格水。于是小A面前出现了一个瀑布。作为平民的小A只好老实巴交地爬山堵水。那么问题来了:我们把这
个瀑布看成是一个n个节点的树,每个节点有权值(爬上去的代价)。小A要选择一些节点,以其权值和作为代价将
这些点删除(堵上),使得根节点与所有叶子结点不连通。问最小代价。不过到这还没结束。小A的朋友觉得这样
子太便宜小A了,于是他还会不断地修改地形,使得某个节点的权值发生变化。不过到这还没结束。小A觉得朋友做
得太绝了,于是放弃了分离所有叶子节点的方案。取而代之的是,每次他只要在某个子树中(和子树之外的点完全
无关)。于是他找到你。
n<=200000,保证任意to都为非负数
Solution
考虑没有修改的情况,设f[i]表示以i为根的子树不能通向叶节点最小代价,h[i]=Σf[son[i]],w[i]为去掉节点i的代价,那么f[i]=min(h[i],w[i])
加上修改操作,我们增大节点i的w会影响fa[i]当且仅当h[fa[i]]+delta<w[fa[i]],并且一定会影响一整条链
那么我们可以轻重链剖分然后线段树记录区间w[i]-h[i]的最小值,我们只需要找到第一个w[i]-h[i]>delta的位置然后区间加即可
不是特别好写,日到底的线段树不是特别优秀
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const LL INF=1e15;
const int N=200005;
const int E=400005;
struct edge {int x,y,next;} e[E];
LL mn[N<<2],tag[N<<2],w[N],h[N],f[N];
int fa[N],bl[N],dep[N],size[N];
int pos[N],dfn[N];
int ls[N],edCnt;
LL read() {
LL x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void dfs1(int now) {
size[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
dep[e[i].y]=dep[now]+1;
fa[e[i].y]=now;
dfs1(e[i].y);
size[now]+=size[e[i].y];
h[now]+=f[e[i].y];
}
if (size[now]==1) h[now]=INF;
f[now]=std:: min(w[now],h[now]);
}
void dfs2(int now,int up) {
pos[now]=++pos[0]; bl[now]=up;
dfn[pos[now]]=now;
int mx=0;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
}
if (!mx) return ;
dfs2(mx,up);
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
}
}
void push_down(int now) {
if (!tag[now]) return ;
tag[now<<1]+=tag[now]; tag[now<<1|1]+=tag[now];
mn[now<<1]-=tag[now]; mn[now<<1|1]-=tag[now];
tag[now]=0;
}
LL get_h(int now,int tl,int tr,int x) {
if (tl!=tr) push_down(now);
if (tl==tr) {
mn[now]=w[dfn[tl]]-tag[now];
return tag[now];
}
LL ret; int mid=(tl+tr)>>1;
if (x<=mid) ret=get_h(now<<1,tl,mid,x);
else ret=get_h(now<<1|1,mid+1,tr,x);
mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
return ret;
}
int modify(int now,int tl,int tr,int l,int r,LL v) {
if (tl!=tr) push_down(now);
int mid=(tl+tr)>>1,ret;
if (tl==l&&tr==r) {
if (mn[now]>=v) {
tag[now]+=v; mn[now]-=v;
return 0;
} else if (l==r) {
tag[now]+=v; mn[now]-=v;
return dfn[l];
}
ret=modify(now<<1|1,mid+1,tr,mid+1,r,v);
if (!ret) ret=modify(now<<1,tl,mid,l,mid,v);
mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
return ret;
}
if (r<=mid) {
ret=modify(now<<1,tl,mid,l,r,v);
} else if (l>mid) {
ret=modify(now<<1|1,mid+1,tr,l,r,v);
} else {
ret=modify(now<<1|1,mid+1,tr,mid+1,r,v);
if (!ret) ret=modify(now<<1,tl,mid,l,mid,v);
}
mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
return ret;
}
void build(int now,int tl,int tr) {
if (tl==tr) {
int x=dfn[tl];
tag[now]=h[x];
mn[now]=w[x]-h[x];
return ;
}
int mid=(tl+tr)>>1;
build(now<<1,tl,mid);
build(now<<1|1,mid+1,tr);
mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
}
void change(int x,LL v) {
if (v<=0) return ;
int ret=0;
while (x) {
ret=modify(1,1,pos[0],pos[bl[x]],pos[x],v);
if (ret) break;
x=fa[bl[x]];
}
if (ret) change(fa[ret],w[ret]-get_h(1,1,pos[0],pos[ret])+v);
}
int main(void) {
int n=read();
rep(i,1,n) w[i]=read();
rep(i,2,n) add_edge(read(),read());
dep[1]=1; dfs1(1); dfs2(1,1);
build(1,1,n);
for (int T=read();T--;) {
char opt[2]; scanf("%s",opt);
if (opt[0]=='Q') {
int x=read();
LL ans=std:: min(get_h(1,1,n,pos[x]),w[x]);
printf("%lld\n", ans);
} else if (opt[0]=='C') {
int x=read(); LL y=read();
w[x]+=y; LL h=get_h(1,1,n,pos[x]);
if (w[x]-y<h) change(fa[x],std:: min(h,w[x])-std:: min(h,w[x]-y));
}
}
return 0;
}