前言
有点懊恼的一个题…
并没有其他那些ZJOI那么毒瘤,看出了关键结论,但最后维护卡在log条虚边的伞兵性质上了。
解析
第一眼:感觉根本不可做啊。
冷静一下,既然它还变态的带修,一定是可以转化成比较形式化的东西的。
对每个节点考虑对答案贡献了多少次,设 sxs_xsx 表示 x 子树内权值之和,mxxmx_xmxx 表示 max(ax,maxu∈sonxsu)\max(a_x,\max_{u\in son_{x}}s_{u})max(ax,maxu∈sonxsu),那么答案的上界显然是 sx−1s_x-1sx−1,但前提是不同子树的权值必须交错出现,因此其实应该是 min(sx−1,2(sx−mxx))\min(s_x-1,2(s_x-mx_x))min(sx−1,2(sx−mxx)),递归的想可以发现这个结论一直都是对的。写一发暴力得到了30分,说明结论没有问题。
考虑如何快速的维护修改。
一个节点 x 收到某个儿子 son “一家独大”的制约当且仅当 2∗sson≥sx+12*s_{son}\ge s_x+12∗sson≥sx+1。显然至多存在一个这样的儿子,定义其为 hsonxhson_xhsonx(特别的,hsonxhson_xhsonx 可以为 x 自己),(x,hsonx)(x,hson_x)(x,hsonx) 这样的边定义为实边,其他边定义为虚边。
考虑对一个节点 x + w,贡献发生改变的必然是一条返祖链。进一步,发现对于返祖链上的一条实边,其父亲端的贡献必然不会改变。
然后我觉的虚实边变来变去我就不会了。
接下来,通过和树剖类似的证明 ,可以得出任意一条返祖链上的虚边最多有 logai\log a_ilogai 条。
所以暴力跳修改所有虚边的贡献即可。
实现上,树剖后开两棵线段树,一棵维护虚实边,一棵维护 sxs_xsx 即可。
时间复杂度 O(nlogn(logn+log∑ai))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:tagll 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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=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;
}
/*
*/