以每个坑种树的收益建一个大根堆
填上一个坑后,向堆加入坑两边收益减去坑的收益,提供反悔的机会
这与网络流很像
用链表存前驱后继
#include<cstdio>
#include<queue>
using namespace std;
struct A{int id,x; };
const int N=2e5+5;
int n,m,pre[N],nxt[N],a[N],ans,fl[N];
bool operator <(A i,A j) { return i.x<j.x; }
priority_queue<A>q;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
if(m+m>n)
{
puts("Error!");
return 0;
}
for(int i=2;i<=n;i++)
pre[i]=i-1;
pre[1]=n;
for(int i=1;i<n;i++)
nxt[i]=i+1;
nxt[n]=1;
for(int i=1;i<=n;i++)
q.push((A){i,a[i]});
while(m--)
{
while(fl[q.top().id])
q.pop();
A t=q.top();
q.pop();
ans+=t.x;
int l=pre[t.id],r=nxt[t.id];
a[t.id]=a[l]+a[r]-t.x;
q.push((A){t.id,a[t.id]});
fl[l]=1; fl[r]=1;
nxt[pre[l]]=nxt[l];
pre[nxt[l]]=pre[l];
nxt[pre[r]]=nxt[r];
pre[nxt[r]]=pre[r];
}
printf("%d\n",ans);
return 0;
}