版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88142611
洛谷传送门
BZOJ传送门
解析:
其实就是给你一颗 ,初始全部都是虚边, 恒为根。给出每个点 的次数,求出所有方案中,切换实链的最大次数。
你问我为什么这个和原题意是等价的?自己对断实链,连实链的情况分类讨论啊。
于是我们现在考虑每个点的实链的变化,显然只有它和它子树内节点的 能够影响到它的实链。而同一个子树内的点的 对它的影响没有区别。
换句话说,每个点的实链切换次数最大化是独立的,互不影响。
显然只有来自当前虚边子树的 或者自己的 能够切换实链。
实际上这是一个经典问题,给出 种颜色的球,每种 个,问将这些球排成一排,相邻的两个颜色不同的最大对数是多少。
令
,则答案是这个东西:
现在考虑证明。
如果最大颜色没有过半的话,我们总是有一个贪心策略,选择和当前位置颜色不同的,剩余球最多的颜色放在下一个位置,可以证明,这样总是能够构造出解。
不然的话,我们将颜色最多的球排成一列,将剩下的球找空隙放进去就行了。
所以不带修改的话直接树形DP就行了。
扫描二维码关注公众号,回复:
5469144 查看本文章
现在考虑带修改。
首先由一个糖水不等式得到:
所以修改位置向上的所有决策已经为 的位置就不可能改变决策或决策的值了。
我们发现这是一条链的结构。
。。。好的这就是LCT。将这条链上的边全部设置成实边。
但是有可能原来决策为 的位置需要改变了啊。
暴力改啊。我们发现,越过一条轻边后的 会翻倍,也就是说轻边最多只有 条,不特意卡的话也就30多,卡的话也就40多,而且还不可能每次访问那么多。
也就是需要在 的时候判断当前边到底能不能修改为实边。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=4e5+5;
int n,m;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int fa[N],son[N][2];
ll sum[N],f[N],val[N],ans;
inline bool which(int u){return son[fa[u]][1]==u;}
inline bool isroot(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline void pushup(int u){sum[u]=sum[son[u][0]]+sum[son[u][1]]+val[u]+f[u];}
inline void Rotate(int u){
int Fa=fa[u],FA=fa[Fa];
bool pos=which(u);
if(!isroot(Fa))son[FA][which(Fa)]=u;
son[Fa][pos]=son[u][!pos];
if(son[Fa][pos])fa[son[Fa][pos]]=Fa;
son[u][!pos]=Fa;
fa[Fa]=u;fa[u]=FA;
pushup(Fa);pushup(u);
}
inline void Splay(int u){
for(int re Fa=fa[u];!isroot(u);Rotate(u),Fa=fa[u])
if(!isroot(Fa))Rotate(which(Fa)==which(u)?Fa:u);
}
inline ll calc(int u,ll t,ll h){
if(son[u][1])return t-h<<1;
if(val[u]*2>t)return t-val[u]<<1;
return t-1;
}
inline void modify(int u,int w){
Splay(u);
ll t=sum[u]-sum[son[u][0]],h=sum[son[u][1]];
ans-=calc(u,t,h);
sum[u]+=w,val[u]+=w;t+=w;
if(h*2<t+1)f[u]+=h,son[u][1]=0;
ans+=calc(u,t,h);pushup(u);
int v=u;
for(u=fa[u];u;u=fa[v=u]){
Splay(u);
t=sum[u]-sum[son[u][0]],h=sum[son[u][1]];
ans-=calc(u,t,h);sum[u]+=w,t+=w,f[u]+=w;
if(h*2<t+1)f[u]+=h,son[u][1]=0,h=0;
if(sum[v]*2>t)f[u]-=sum[v],son[u][1]=v,h=sum[v];
ans+=calc(u,t,h);pushup(u);
}
}
void dfs(cs int &u){
sum[u]=val[u];
int hson=0;
ll mx=val[u];
for(int &e=last[u],v=to[e];e;v=to[e=nxt[e]])
if(v^fa[u]){
fa[v]=u;
dfs(v);
sum[u]+=sum[v];
if(mx<=sum[v])mx=sum[hson=v];
}
ans+=min(sum[u]-1,sum[u]-mx<<1);
if(mx*2>=sum[u]+1)son[u][1]=hson;
f[u]=sum[u]-val[u]-sum[son[u][1]];
}
signed main(){
n=getint(),m=getint();
for(int re i=1;i<=n;++i)val[i]=getint();
for(int re i=1;i<n;++i)addedge(getint(),getint());
dfs(1);cout<<ans<<"\n";
int u,w;
while(m--){
u=getint(),w=getint();
modify(u,w);
cout<<ans<<"\n";
}
return 0;
}