永恒的一氧化碳大爷在讨论版里发了个单log的做法,还没来得及看……
先写个链剖再说
考虑没有修改的情况,我们可以树DP,f[x]表示把x的子树截断的最小代价,v[x]表示截断每个点的代价,然后我们求出每个点的s[x],代表x的所有儿子节点的f之和,f[x]就等于min(v[x],s[x])
考虑修改,一次修改操作后,v[x]会增加,f[x]可能增加,可能不变,如果f[x]增加了d,那么从x到根的一段路径上的点的s值和f值都会增加d,直到第一个有v[x]-s[x]<=d的点,即s[x]在加d之后会变得比v[x]大,或原来v[x]就小于等于s[x],则f[x]不再等于s[x]+d,而改为v[x],则增加量会改变一次,我们继续对顶上的路径重复上述过程,直到增加量为0或者到根
对于一次处理增加操作,我们可以用链剖加线段树,支持区间加和区间查询v[x]-s[x]的最小值,在线段树上爬来找到第一个v[x]-s[x]<=d的点
由于修改操作的增加量是非负的,并且每次只更改一个点,所以至多有n+m次s[x]变得比v[x]大的时刻,处理一个这样的时刻是O(log^2 n)的,所以总复杂度O((n+m) log^2 n)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 200010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct vec{
ll to;
ll fro;
};
vec mp[MAXN*2];
ll tai[MAXN],cnt;
ll n,m;
ll v[MAXN],s[MAXN],f[MAXN];
ll fa[MAXN],son[MAXN],tp[MAXN],siz[MAXN],dfn[MAXN],ndf[MAXN],tim;
ll mn[MAXN<<2],ch[MAXN<<2];
inline void be(ll x,ll y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
inline void bde(ll x,ll y){
be(x,y);
be(y,x);
}
void dfs(ll x){
ll i,y;
siz[x]=1;
bool flag=0;
s[x]=INF;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(!siz[y]){
fa[y]=x;
dfs(y);
if(!flag){
flag=1;
s[x]=0;
}
s[x]+=f[y];
siz[x]+=siz[y];
if(siz[son[x]]<siz[y]){
son[x]=y;
}
}
}
f[x]=min(v[x],s[x]);
}
void dfs2(ll x,ll z){
ll i,y;
ndf[dfn[x]=++tim]=x;
tp[x]=z;
if(son[x]){
dfs2(son[x],z);
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(!dfn[y]){
dfs2(y,y);
}
}
}
}
inline void ud(ll x){
mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
inline void toch(ll x,ll y){
ch[x]+=y;
mn[x]-=y;
}
inline void pd(ll x){
if(ch[x]){
toch(x<<1,ch[x]);
toch(x<<1|1,ch[x]);
ch[x]=0;
}
}
void build(ll x,ll y,ll z){
if(y==z){
mn[x]=v[ndf[y]]-s[ndf[y]];
return ;
}
ll mid=y+z>>1;
build(x<<1,y,mid);
build(x<<1|1,mid+1,z);
ud(x);
}
ll change(ll x,ll y,ll z,ll l,ll r,ll cv){
if(y==z){
toch(x,cv);
if(mn[x]+cv<=cv){
return ndf[y];
}else{
return 0;
}
}
pd(x);
ll t=0;
ll mid=y+z>>1;
if(y==l&&z==r){
if(mn[x]>cv){
toch(x,cv);
return 0;
}
}
if(r<=mid){
t=change(x<<1,y,mid,l,r,cv);
}else if(l>mid){
t=change(x<<1|1,mid+1,z,l,r,cv);
}else{
t=change(x<<1|1,mid+1,z,mid+1,r,cv);
if(!t){
t=change(x<<1,y,mid,l,mid,cv);
}
}
ud(x);
return t;
}
ll ask(ll x,ll y,ll z,ll p){
if(y==z){
return mn[x];
}
pd(x);
ll mid=y+z>>1;
if(p<=mid){
return ask(x<<1,y,mid,p);
}else{
return ask(x<<1|1,mid+1,z,p);
}
}
void tochange(ll x,ll y){
if(y<=0||!x){
return ;
}
while(x){
ll t=change(1,1,n,dfn[tp[x]],dfn[x],y);
if(!t){
x=fa[tp[x]];
}else{
tochange(fa[t],ask(1,1,n,dfn[t])+y);
return ;
}
}
}
int main(){
ll i,x,y;
char o[2];
scanf("%lld",&n);
for(i=1;i<=n;i++){
scanf("%lld",&v[i]);
}
for(i=1;i<n;i++){
scanf("%lld%lld",&x,&y);
bde(x,y);
}
dfs(1);
dfs2(1,1);
build(1,1,n);
scanf("%lld",&m);
while(m--){
scanf("%s",o);
if(o[0]=='Q'){
scanf("%lld",&x);
ll s=v[x]-ask(1,1,n,dfn[x]);
printf("%lld\n",min(s,v[x]));
}
if(o[0]=='C'){
scanf("%lld%lld",&x,&y);
if(!y){
continue ;
}
v[x]+=y;
change(1,1,n,dfn[x],dfn[x],-y);
ll s=v[x]-ask(1,1,n,dfn[x]);
f[x]=min(v[x],s);
tochange(fa[x],f[x]-v[x]+y);
}
}
return 0;
}
/*
5
5 7 4 1 5
2 1
3 2
4 3
5 3
5
C 3 10
C 1 6
Q 1
*/