种树 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; }