bzoj2151: 种树(贪心+堆)

35 篇文章 0 订阅
4 篇文章 0 订阅

题目传送门

解法:
今天才学这种经典做法。。
如果选最大的然后删除两边很显然这种策略是错误的。
因为有可能两边加起来更优。

那么上面的做法是无法反悔的。。
给他一个反悔的机会。
那么就是:
假设选了i,那么删除i前后的两个点。
然后把i这个点的权值变为a[前]+a[后]-a[i]。
这样再选i的话就表示反悔了选了前后两个。
维护一下这个位置是否删除。这个位置的前一个未被删除的是哪个。后一个未被删除的是哪个就行了。
具体看代码。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<iostream>
using namespace std;
struct node {
    int w,c;node() {w=c=0;}
    friend bool operator <(node n1,node n2){return n1.c<n2.c;}
};priority_queue<node> a;
int q[210000],h[210000],n,m,s[210000];bool v[210000];
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {scanf("%d",&s[i]);q[i]=i-1;h[i]=i+1;node ss;ss.c=s[i];ss.w=i;a.push(ss);}
    if(m*2>n){printf("Error!\n");return 0;}
    q[1]=n;h[n]=1;memset(v,false,sizeof(v));int ans=0;
    for(int i=1;i<=m;i++) {
        while(v[a.top().w]==true)a.pop();
        node t=a.top();a.pop();ans+=t.c;int l=q[t.w],r=h[t.w];
        node p;p.w=t.w;v[l]=true;p.c+=s[l];v[r]=true;p.c+=s[r];p.c-=t.c;
        s[t.w]=p.c;q[t.w]=q[l];h[q[l]]=t.w;h[t.w]=h[r];q[h[r]]=t.w;a.push(p);
    }printf("%d\n",ans);
    return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值