51nodP1380 夹克老爷的逢三抽一

此题的核心在于如何实现反悔操作.

我们可以在选出当前最优并删去左右节点后,在当前最优的节点处再次添加一个\(a[r[i]]+a[l[i]]-a[i]\)的点,如果再次选这个点就意味着一次反悔.

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define pli pair<ll, int>
using namespace std;
typedef long long ll;
const int O = 1e5 + 10;
template<class TT>
il TT read() {
	TT o = 0,fl = 1; char ch = getchar();
	while (!isdigit(ch) && ch != '-') ch = getchar();
	if (ch == '-') fl = -1, ch = getchar();
	while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
	return fl * o;
}
ll ans, a[O];
set<pli >s;
int n, lst[O], nxt[O];
il void Delete(int u) {
	s.erase(pli(-a[u], u));
	lst[nxt[u]] = lst[u];
	nxt[lst[u]] = nxt[u];
}
int main() {
	n = read<int>();
	for (int i = 1; i <= n; ++i) {
		a[i] = read<ll>();
		lst[i % n + 1] = i;
		nxt[i] = i % n + 1;
		s.insert(pli(-a[i], i));
	}
	n /= 3;
	for (int i = 1; i <= n; ++i) {
		int u = s.begin()->second;
		ll y = a[lst[u]] + a[nxt[u]];
		Delete(lst[u]); Delete(nxt[u]);
		ans += a[u];
		s.erase(pli(-a[u], u));
		a[u] = y - a[u];
		s.insert(pli(-a[u], u));
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2019-10-17 23:10  wuhan2005  阅读(58)  评论(0编辑  收藏  举报