BZOJ4886 [Lydsy2017年5月月赛]叠塔游戏

博客内容探讨了BZOJ4886问题的解决方案,强调关键在于确保横放塔的长度不相同。通过将权值视为节点并建立有向边连接,目标是最优化边权总和。文章指出,每个节点的出度不超过1,且每个连通组件要么是树形结构要么是环套树。证明了在一个连通块内不可能存在两个环,因为那样会导致某个节点出度超过1。最后,将边的贡献转换为节点贡献,对于环套树结构,节点贡献是(度数-1)乘以权值,而树结构中,最大权值节点可以额外贡献自身的权值。
摘要由CSDN通过智能技术生成

可以发现我们不用管什么权值递增,只要保证横着放的长度互不相同就可以

把权值看成点,一个矩形就是在长和宽之间连一条边

那么我们就要给每条边定一个向,保证每个点出度最多为1,一条有向边的权值就等于其指向的点的权值,最大化边权和

因为题目保证了有解,所以每个连通块要么是树,要么是环套树

因为如果一个连通块里有两个环的话那么至少有一个点出度为二

证明就是如果所有点出度都<=1的话那就是环套树了,只有一个环,矛盾

我们把边对答案的贡献转换到点上,对于环套树连通块,每个点的贡献就是(度数-1)乘权值,对于树的连通块,令权值最大的点为根,他还可以额外做点权那么多的贡献

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 250010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
int n;
int a[MAXN],b[MAXN];
int tls[MAXN*2],tln,mx;
map<int,int>h;
int g[MAXN*2];
int f[MAXN*2];
bool d[MAXN*2];
int mxv[MAXN*2];
ll ans;
int fa(int x){
	return f[x]==x?x:f[x]=fa(f[x]);
}
int main(){
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a[i],&b[i]);
		tls[++tln]=a[i];
		tls[++tln]=b[i];
	}
	sort(tls+1,tls+tln+1);
	for(i=1;i<=tln;i++){
		if(tls[i]!=tls[i-1]){
			g[h[tls[i]]=++mx]=tls[i];
		}
	}
	for(i=1;i<=mx;i++){
		f[i]=i;
		mxv[i]=g[i];
		ans-=g[i];
	}
	for(i=1;i<=n;i++){
		ans+=a[i]+b[i];
		int ta=h[a[i]],tb=h[b[i]];
		if(fa(ta)!=fa(tb)){
			d[fa(tb)]|=d[fa(ta)];
			mxv[fa(tb)]=max(mxv[fa(tb)],mxv[fa(ta)]);
			f[fa(ta)]=fa(tb);
		}else{
			d[fa(ta)]=1;
		}
	}
	for(i=1;i<=mx;i++){
		if(fa(i)==i&&!d[i]){
			ans+=mxv[i];
		}
	}
	printf("%lld\n",ans);
	return 0;
}

/*

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值