USACO superbull(MST)

题意:n支队伍,每支队伍权值a[i],队伍i和队伍j打比赛会产生a[i] xor a[j]这么多精彩度,但每举行一场比赛你必须淘汰其中一支队伍,淘汰的队伍不能再参赛,请你安排一系列比赛使得最后能够产生冠军,并且使得精彩度最大。n<=2000。

容易发现最多打(n-1)场比赛。我考试时乱做的,就把所有边排序选前n-1条。

其实n-1条边连接了n个点,很明显是一棵树,所以跑一下最大生成树就行了。由于是完全图,所以产生的边会很对,用prim比kruskal更优。


然后实现的时候我用的自创的用来优化dijkstra的数据结构,可以把空间复杂度严格限制在O(n),在完全图中效果特别明显,用堆的都是几十MB,我1MB,并且快很多。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
const int MAXN = 2005;
int a[MAXN], N;

int dis[MAXN], maxp[MAXN*2];
bool used[MAXN];
inline void pushup(int&p) {
	int &r = maxp[p];
	r = p * !used[p];
	if (dis[maxp[p<<1]] > dis[r]) r = maxp[p<<1];
	if (dis[maxp[p<<1|1]] > dis[r]) r = maxp[p<<1|1];
}
void relax(int p, int d) {
	if (d < dis[p]) return;
	dis[p] = d;
	for (int i = p; i; i>>=1) pushup(i);
}
void finish(int p) {
	used[p] = 1;
	for (int i = p; i; i>>=1) pushup(i);
}

LL Prim() {
	relax(1, 0);
	LL res = 0;
	for (int i = 1; i<=N; ++i)
	{
		int u = maxp[1];
		res += dis[u];
		finish(u);
		for (int j = 1; j<=N; ++j)
			if (j != u && !used[j]) relax(j, a[j]^a[u]);
	}
	return res;
}

int main()
{
	cin >> N;
	for (int i = 1; i<=N; ++i) cin >> a[i];
	cout << Prim() << '\n';
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值