种树 BZOJ2151 模拟费用流

分析:

我们如果选择点i,那么我们不能选择i-1和i+1,如果没有这个限制,直接贪心就可行,而加上这个限制,我们考虑同样贪心,每次选择i后,将点i-1,i+1从双向链表中删除,并且将-a[i]+a[i-1]+a[i+1]推入堆中,处理K次,得到最优答案

附上代码:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
using namespace std;
#define N 200005
int a[N],ans,n,m,pre[N],nxt[N],vis[N];
priority_queue<pair<int,int> >q;
int main()
{
	// freopen("tree.in","r",stdin);
	// freopen("tree.out","w",stdout);
	scanf("%d%d",&n,&m);
	if(m>(n>>1))
	{
		puts("Error!");
		return 0;
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);pre[i]=i-1;
		q.push(make_pair(a[i],i));nxt[i]=i+1;
	}
	pre[1]=n,nxt[n]=1;
	while(m)
	{
		int k=q.top().second;q.pop();
		if(vis[k])continue;ans+=a[k];
		a[k]=a[pre[k]]+a[nxt[k]]-a[k];
		vis[pre[k]]=1;vis[nxt[k]]=1;
		pre[nxt[nxt[k]]]=k;nxt[k]=nxt[nxt[k]];
		nxt[pre[pre[k]]]=k;pre[k]=pre[pre[k]];
		q.push(make_pair(a[k],k));m--;
	}
	printf("%d\n",ans);
	return 0;
}

  

posted @ 2018-05-23 21:02  Winniechen  阅读(353)  评论(0编辑  收藏  举报