BZOJ 2151 种树(可反悔贪心,链表)BZOJ千题计划就图一乐

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2151 种树(可反悔贪心,链表)BZOJ千题计划就图一乐相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


题目链接

https://hydro.ac/d/bzoj/p/2151

hydro 的 BZOJ 修复工程

Problem

A 城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出 n n n 个种树的位置,顺时针编号 1 1 1 n n n 。并且每个位置都有一个美观度 a i a_i ai ,如果在这里种树就可以得到这 a i a_i ai 的美观度。但由于 A 城市土壤肥力欠佳,两棵树决不能种在相邻的位置( i i i 号位置和 i + 1 i+1 i+1 号位置叫相邻位置。值得注意的是 1 1 1 号和 n n n 号也算相邻位置!)。最终市政府给园林部门提供了 m m m 棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将 m m m 棵树苗全部种上,输出 Error!

n ≤ 2 × 1 0 5 n\\le 2\\times 10^5 n2×105 m ≤ n m\\leq n mn − 1 0 3 ≤ a i ≤ 1 0 3 -10^3\\leq a_i\\leq 10^3 103ai103

Solution

这道题一眼就可以看出来显然是可以贪心的,大致是一个带反悔的贪心。

考虑维护一个大根堆,从所有坑中选取价值最大的,使用这个坑。

但是当前最优不一定保证局面最优,可能当前这个坑 x x x 的价值虽然是最大的,但它两边的坑的价值之和 w l + w r w_l+w_r wl+wr 要大于中间的这个坑的价值 w x w_x wx,所以我们需要提供一次反悔的机会,选择中间的坑之后,若选择两边的坑,显然要丢掉中间的这个坑,得到的权值 z = w l + w r − w x z=w_l+w_r-w_x z=wl+wrwx,我们将 z z z 丢进大根堆里,继续维护最优值即可。

题目要求选择坑 x x x ,它左右相邻的两个坑就不能使用了,所以我们可以建一个双向链表维护一下每个结点的前驱和后继,在删点的时候把链表合并一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> PII;
using ll = long long;
const int maxn = 3e5 + 6;
int n, m, s, t;
ll ans;
int pre[maxn], nex[maxn];
int w[maxn];
priority_queue <PII> q;
bool vis[maxn];

void change(int x)
{
	vis[x] = 1;
	pre[nex[x]] = pre[x];
	nex[pre[x]] = nex[x];
	pre[x] = nex[x] = 0;
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) 
		scanf("%d", &w[i]), q.push({w[i], i});
	if(n / 2 < m) 
		return 0 * puts("Error!");
	nex[n] = 1, pre[1] = n;
	for (int i = 1; i < n; ++ i) nex[i] = i + 1;
	for (int i = 2; i <= n; ++ i) pre[i] = i - 1;
	while(m -- ) {  
		while(vis[q.top().second])
			q.pop();
		PII x = q.top();
		q.pop();
		ans += x.first; 
		int pos = x.second;
		int l = pre[pos], r = nex[pos];
		w[pos] = w[l] + w[r] - w[pos];
		change(l), change(r);
		q.push({w[pos], pos});
	}
	cout << ans << endl;
	return 0;
} 

以上是关于BZOJ 2151 种树(可反悔贪心,链表)BZOJ千题计划就图一乐的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2151: 种树贪心+堆

BZOJ_2151_种树_贪心+堆+链表

BZOJ2151 种树 [贪心+链表]

BZOJ 2151 2151: 种树 (贪心+堆)

bzoj2151种树(堆/优先队列+双向链表)

bzoj2151: 种树(双向链表+堆)