前言
有点懊恼的一个题…
并没有其他那些ZJOI那么毒瘤,看出了关键结论,但最后维护卡在log条虚边的伞兵性质上了。
解析
第一眼:感觉根本不可做啊。
冷静一下,既然它还变态的带修,一定是可以转化成比较形式化的东西的。
对每个节点考虑对答案贡献了多少次,设
s
x
s_x
sx 表示 x 子树内权值之和,
m
x
x
mx_x
mxx 表示
max
(
a
x
,
max
u
∈
s
o
n
x
s
u
)
\max(a_x,\max_{u\in son_{x}}s_{u})
max(ax,maxu∈sonxsu),那么答案的上界显然是
s
x
−
1
s_x-1
sx−1,但前提是不同子树的权值必须交错出现,因此其实应该是
min
(
s
x
−
1
,
2
(
s
x
−
m
x
x
)
)
\min(s_x-1,2(s_x-mx_x))
min(sx−1,2(sx−mxx)),递归的想可以发现这个结论一直都是对的。写一发暴力得到了30分,说明结论没有问题。
考虑如何快速的维护修改。
一个节点 x 收到某个儿子 son “一家独大”的制约当且仅当
2
∗
s
s
o
n
≥
s
x
+
1
2*s_{son}\ge s_x+1
2∗sson≥sx+1。显然至多存在一个这样的儿子,定义其为
h
s
o
n
x
hson_x
hsonx(特别的,
h
s
o
n
x
hson_x
hsonx 可以为 x 自己),
(
x
,
h
s
o
n
x
)
(x,hson_x)
(x,hsonx) 这样的边定义为实边,其他边定义为虚边。
考虑对一个节点 x + w,贡献发生改变的必然是一条返祖链。进一步,发现对于返祖链上的一条实边,其父亲端的贡献必然不会改变。
然后我觉的虚实边变来变去我就不会了。
接下来,通过和树剖类似的证明 ,可以得出任意一条返祖链上的虚边最多有
log
a
i
\log a_i
logai 条。
所以暴力跳修改所有虚边的贡献即可。
实现上,树剖后开两棵线段树,一棵维护虚实边,一棵维护
s
x
s_x
sx 即可。
时间复杂度
O
(
n
log
n
(
log
n
+
log
∑
a
i
)
)
O(n\log n(\log n+\log {\sum a_i}))
O(nlogn(logn+log∑ai))。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=4e5+100;
const int mod=1e9+7;
bool mem1;
inline ll ksm(ll x,ll k){
ll res(1);
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int n,m;
struct seg{
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
ll sum[N<<2],laz[N<<2];
inline void pushup(int k){
sum[k]=sum[ls]+sum[rs];
}
inline void add(int k,int l,int r,ll w){
sum[k]+=(r-l+1)*w;
laz[k]+=w;
}
inline void pushdown(int k,int l,int r){
ll o=laz[k];laz[k]=0;
if(!o) return;
add(ls,l,mid,o);
add(rs,mid+1,r,o);
return;
}
void change(int k,int l,int r,int x,int y,ll w){
if(x<=l&&r<=y){
add(k,l,r,w);return;
}
pushdown(k,l,r);
if(x<=mid) change(ls,l,mid,x,y,w);
if(y>mid) change(rs,mid+1,r,x,y,w);
pushup(k);
}
int findpre(int k,int l,int r,int p){
if(!k) exit(0);
//debug("k=%d (%d %d) p=%d\n",k,l,r,p);
if(!sum[k]) return 0;
if(l==r) return l;
if(p<=mid) return findpre(ls,l,mid,p);
pushdown(k,l,r);
int o=findpre(rs,mid+1,r,p);
if(o) return o;
else return findpre(ls,l,mid,p);
}
ll ask(int k,int l,int r,int p){
if(l==r) return sum[k];
pushdown(k,l,r);
if(p<=mid) return ask(ls,l,mid,p);
else return ask(rs,mid+1,r,p);
}
}t1,t2;
//t1:s
//t2:tag
ll a[N],s[N],mx[N],ans;
int hson[N],siz[N],top[N],dep[N],fa[N],dfn[N],pos[N],tim;
bool tag[N];
vector<int>e[N];
void dfs1(int x,int f){
siz[x]=1;
dep[x]=dep[f]+1;
fa[x]=f;
s[x]=mx[x]=a[x];hson[x]=x;
for(int to:e[x]){
if(to==f) continue;
dfs1(to,x);
siz[x]+=siz[to];
s[x]+=s[to];
if(s[to]>mx[x]){
hson[x]=to;
mx[x]=s[to];
}
}
ans+=min(s[x]-1,2*(s[x]-mx[x]));
ll sh=hson[x]==x?a[x]:s[hson[x]];
if(2*sh<s[x]+1) hson[x]=0;
if(hson[x]&&hson[x]!=x) tag[hson[x]]=1;
return;
}
void dfs2(int x,int tp){
//debug("x=%d tp=%d\n",x,tp);
top[x]=tp;
dfn[++tim]=x;pos[x]=tim;
int son=0;
for(int to:e[x]){
if(to==fa[x]) continue;
if(siz[to]>siz[son]) son=to;
}
if(son) dfs2(son,tp);
for(int to:e[x]){
if(to==fa[x]||to==son) continue;
dfs2(to,to);
}
return;
}
void init(){
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=n;i++){
t1.change(1,1,n,pos[i],pos[i],s[i]);
if(i>1&&!tag[i]) t2.change(1,1,n,pos[i],pos[i],1);
//printf("i=%d hson=%d s=%lld tag=%d\n",i,hson[i],s[i],tag[i]);
}
return;
}
inline ll calc(ll s,ll mx){
return min(s-1,2*(s-mx));
}
inline void upd(int x,int w){
int ori=x;
//printf("upd: x=%d w=%d\n",x,w);
if(hson[x]!=x){
int son=hson[x];
ll sh=son?t1.ask(1,1,n,pos[son]):0,sx=t1.ask(1,1,n,pos[x]);
ans-=calc(sx,sh);
ans+=calc(sx+w,max(sh,a[x]+w));
//printf(" x=%d son=%d sh=%lld ans=%lld\n",x,son,sh,ans);
if(son&&2*sh<(sx+w)+1){
t2.change(1,1,n,pos[son],pos[son],1);
hson[x]=0;
}
if(2*(a[x]+w)>(sx+w)+1){
hson[x]=x;
}
}
while(x){
int p=t2.findpre(1,1,n,pos[x]);
if(p==0||p<pos[top[x]]) x=fa[top[x]];
else{
x=dfn[p];
int son=hson[fa[x]];
ll sf=t1.ask(1,1,n,pos[fa[x]]),
sh=son?son==fa[x]?a[fa[x]]:t1.ask(1,1,n,pos[son]):0,sx=t1.ask(1,1,n,pos[x]);
ans-=calc(sf,sh);
ans+=calc(sf+w,max(sx+w,sh));
//printf(" x=%d son=%d sf=%lld sh=%lld sx=%lld p=%d ans=%lld\n",x,son,sf,sh,sx,p,ans);
if(son&&2*sh<(sf+w)+1){
t2.change(1,1,n,pos[son],pos[son],1);
hson[fa[x]]=0;
}
if(2*(sx+w)>=(sf+w)+1){
t2.change(1,1,n,pos[x],pos[x],-1);
hson[fa[x]]=x;
}
x=fa[x];
}
}
x=ori;
a[x]+=w;
while(x){
t1.change(1,1,n,pos[top[x]],pos[x],w);
x=fa[top[x]];
}
return;
}
bool mem2;
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
init();
printf("%lld\n",ans);
for(int i=1;i<=m;i++){
int x=read(),w=read();
upd(x,w);
printf("%lld\n",ans);
}
return 0;
}
/*
*/