2019.03.04【ZJOI2018】【BZOJ5212】【洛谷P4338】历史(假LCT)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88142611

洛谷传送门

BZOJ传送门


解析:

其实就是给你一颗 L C T LCT ,初始全部都是虚边, 1 1 恒为根。给出每个点 a c c e s s access 的次数,求出所有方案中,切换实链的最大次数。

你问我为什么这个和原题意是等价的?自己对断实链,连实链的情况分类讨论啊。

于是我们现在考虑每个点的实链的变化,显然只有它和它子树内节点的 a c c e s s access 能够影响到它的实链。而同一个子树内的点的 a c c e s s access 对它的影响没有区别。

换句话说,每个点的实链切换次数最大化是独立的,互不影响。

显然只有来自当前虚边子树的 a c c e s s access 或者自己的 a c c e s s access 能够切换实链。

实际上这是一个经典问题,给出 n n 种颜色的球,每种 a i a_i 个,问将这些球排成一排,相邻的两个颜色不同的最大对数是多少。

t = i = 1 n a i , h = max { a i } t=\sum\limits_{i=1}^na_i,h=\max\{a_i\} ,则答案是这个东西:
min ( t 1 , 2 ( t h ) ) \min(t-1,2*(t-h))

现在考虑证明。

如果最大颜色没有过半的话,我们总是有一个贪心策略,选择和当前位置颜色不同的,剩余球最多的颜色放在下一个位置,可以证明,这样总是能够构造出解。

不然的话,我们将颜色最多的球排成一列,将剩下的球找空隙放进去就行了。

所以不带修改的话直接树形DP就行了。

扫描二维码关注公众号,回复: 5469144 查看本文章

现在考虑带修改。

首先由一个糖水不等式得到: h + w t + w > h t \frac{h+w}{t+w} > \frac{h}{t}

所以修改位置向上的所有决策已经为 2 ( t h ) 2*(t-h) 的位置就不可能改变决策或决策的值了。

我们发现这是一条链的结构。

。。。好的这就是LCT。将这条链上的边全部设置成实边。

但是有可能原来决策为 t 1 t-1 的位置需要改变了啊。

暴力改啊。我们发现,越过一条轻边后的 t t 会翻倍,也就是说轻边最多只有 O ( log a i ) O(\log \sum{a_i}) 条,不特意卡的话也就30多,卡的话也就40多,而且还不可能每次访问那么多。

也就是需要在 a c c e s s access 的时候判断当前边到底能不能修改为实边。


#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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/88142611