bzoj 2151: 种树【贪心+堆】

和数据备份差不多

设二元组(i,a[i]),开一个大根堆把二元组塞进去,以len排序,每次取出一个二元组

因为单纯的贪心是不行的,所以设计一个“反悔”操作。

记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=a[pr[x]]+a[ne[x]]-a[x],相应修改前驱后继,然后“删掉”前驱后继的二元组,这样的意思是如果再次选了修改过的二元组x,就意味着退还掉x,选择它的前驱后继,易证这样个数和ans都不会受影响。

至于用stl如何执行删除?可以把要的点的len设为inf,这样每次操作前先弹掉x与len[x]不符的点就相当于删除操作了。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=200005;
int n,m,ans,a[N],pr[N],ne[N];
struct qwe
{
    int p,v;
    qwe(int P=0,int V=0)
    {
        p=P,v=V;
    }
    bool operator < (const qwe &b) const
    {
        return v<b.v;
    }
};
priority_queue<qwe>q;
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        q.push(qwe(i,a[i]));
        pr[i]=i-1,ne[i]=i+1;
    }
    pr[1]=n,ne[n]=1;
    if(2*m>n)
    {
        puts("Error!");
        return 0;
    }
    for(int i=1;i<=m;i++)
    {
        while(!q.empty()&&a[q.top().p]!=q.top().v)
            q.pop();
        int x=q.top().p,l=pr[x],r=ne[x];
        q.pop();
        ans+=a[x];
        pr[ne[x]=ne[r]]=x;
        ne[pr[x]=pr[l]]=x;
        a[x]=a[l]+a[r]-a[x];
        a[l]=a[r]=1e9;
        q.push(qwe(x,a[x]));
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9643243.html

时间: 2024-08-04 17:52:53

bzoj 2151: 种树【贪心+堆】的相关文章

BZOJ 2151 种树 贪心+优先队列+HASH

题意:链接 方法:贪心+优先队列 解析: 首先裸上贪最大的肯定不对. DP可行么?可行,两个数组一个记录选一个记录不选好像差不多n^2? 不过还是想想贪心. 贪最大的为什么不对? 因为有可能它旁边的两个加起来比它更优越? 所以能否找到一点关系呢? 既然话都说到这了,两个加起来可能更优越. 所以我们在选了最大的之后是否应该回推一个值呢?代表选旁边俩. 我们发现选旁边俩是两个单位,选一个是一个单位,如果我们推回去某个值后这个值相当于对应删去一个单位选两个单位,即增加一个单位,这显然不会影响最终我们选

BZOJ 2151 种树

贪心+priority_queue. #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 200050 using namespace std; long long n,val[maxn],ans=0,m; bool vis[maxn]; struct node { long long w,pos; friend bool operator &l

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

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

种树(贪心)

2151: 种树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 714  Solved: 397[Submit][Status][Discuss] Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i

【bzoj4198】[Noi2015]荷马史诗 贪心+堆

题目描述 追逐影子的人,自己就是影子. ——荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛>和<伊利亚特>组成的鸿篇巨制<荷马史诗>实在是太长了,Allison 想通过一种编码方式使得它变得短一些. 一部<荷马史诗>中有 n 种不同的单词,从 1 到 n 进行编号.其中第 i 种单词出现的总次数为 wi.Allison 想要用 k 进制串 si 来替换第 i

【贪心+堆】XMU 1584 小明的烦恼

题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1584 题目大意: 给n(n<=100 000)个任务的耗时和截至时间,问最少不能完成几个任务. 题目思路: [贪心+堆] 一开始想贪心但是没想到要加个堆,又跪了. 首先按照结束时间排序,结束时间早的肯定优先考虑. 如果当前的任务无法完成,就将当前任务和之前已经做了的任务中耗时最长的取消掉,改做当前任务 (如果当前任务就是耗时最长的则不用加当前任务,因为取消一个换另一个结果不会更差,只

【bzoj4425】[Nwerc2015]Assigning Workstations分配工作站 贪心+堆

题目描述 佩内洛普是新建立的超级计算机的管理员中的一员. 她的工作是分配工作站给到这里来运行他们的计算研究任务的研究人员. 佩内洛普非常懒惰,不喜欢为到达的研究者们解锁机器. 她可以从在她的办公桌远程解锁这些机器,但她并不觉得这卑贱的任务配得上她,所以她决定忽略安全指南偷偷懒.她可以直接地要求,研究者在他们离开时不用锁定自己的工作站,然后把未在使用且还在未锁定状态的工作站分配给新来的研究人员. 这样,她只需要为每一个工作站第一次被使用所属的研究员解锁工作站,这对佩内洛普的工作来说是一个巨大的改善

BZOJ 1029 建筑抢修(贪心堆)

原题代号:BZOJ 1029 原题描述: 建筑抢修 小刚在玩JSOI提供的一个称之为"建筑抢修"的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏.现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间.同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑.如果某个建筑在一段时间之内没有完全修理完毕,这个建

BZOJ 1029 JSOI2007 建筑抢修 贪心+堆

题目大意:n个建筑须要抢修.第i个建筑须要T1时间抢修.必须在T2时间之前抢修完成.求最多能抢修多少建筑 首先我们对T2排序 然后依次修理 可是这样贪心显然是不对的 比方说这组数据: 5 10 10 10 20 2 21 2 21 2 21 贪心仅仅能修理前两个.而实际上最多能够修理4个 于是我们考虑修正贪心算法 比方说这组数据,当我们枚举到3的时候.尽管已经无法修理很多其它了,可是我们能够取消修理建筑1而改修理3.这样尽管不能更新ans 可是能够为后面的建筑节省时间 所以做法就非常明白了 我们