【bzoj2151】种树(堆/优先队列+双向链表)

  题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2151

  这道题因为优先队列不怎么会用,而且手写堆的代码也不长,也想复习一下手写堆的写法……结果……WAWAWAWAW……看来我对堆的认识还是太浅薄了……

  这道题,如果没有限制不能选相邻的两个位置,那就肯定是贪心地选择m个美观度最大的位置种树。然而这里加了限制,那么我们可以注意到,如果一个美观度比较大的位置不被选上,一定是因为它两边的位置都被选了。

  于是我们可以把n个美观度压进一个堆里,每次把美观度最大的位置取出来更新答案,然后它两边的位置删掉,把这个位置的美观度修改成(左边的美观度+右边的美观度-原美观度),就是选这个位置与选两边位置的权值差。

  如果细节没有打错,然后就可以愉快地AC这道题了。

  跑的慢也不会赢的代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define inf 1<<30;
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
ll read()
{
    ll tmp=0; char f=1,c=getchar();
    while(c<‘0‘||‘9‘<c){if(c==‘-‘)f=-1; c=getchar();}
    while(‘0‘<=c&&c<=‘9‘){tmp=tmp*10+c-‘0‘; c=getchar();}
    return tmp*f;
}
using namespace std;
struct data{
    int w,id;
}hp[200010];
int l[200010],r[200010],pos[200010];
int n,m,tot=0;
void swap(int x,int y)
{
    data tmp=hp[x]; hp[x]=hp[y]; hp[y]=tmp;
    pos[hp[x].id]=x; pos[hp[y].id]=y;
}
void add(int id,int w)
{
    hp[++tot].id=id; hp[tot].w=w; pos[id]=tot;
    for(int now=tot;now>1&&hp[now].w>hp[now>>1].w;now>>=1)swap(now,now>>1);
}
void sift(int x)
{
    int now=x;
    while(now<<1<=tot){
        int ne=now<<1;
        if(ne<tot&&hp[ne].w<hp[ne+1].w)++ne;
        if(hp[ne].w>hp[now].w)swap(ne,now),now=ne;
        else break;
    }
}
void del(int id)
{
    hp[pos[id]].w=-inf; sift(pos[id]);
    r[l[id]]=r[id]; l[r[id]]=l[id];
}
int main()
{
    int i;
    n=read(); m=read();
    if(n<m*2){
        printf("Error!\n"); return 0;
    }
    for(i=1;i<=n;i++)add(i,read()),l[i]=i-1,r[i]=i+1;
    l[1]=n; r[n]=1;
    ll ans=0;
    while(m--){
        ans+=hp[1].w;
        int id=hp[1].id;
        hp[1].w=hp[pos[l[id]]].w+hp[pos[r[id]]].w-hp[1].w; sift(1);
        del(l[id]); del(r[id]);
    }
    printf("%lld\n",ans);
    return 0;
}

bzoj2151

时间: 2024-10-01 03:29:16

【bzoj2151】种树(堆/优先队列+双向链表)的相关文章

堆 (优先队列)举例

*/--> pre.src {background-color: Black; color: White;} 堆 (优先队列)举例 题目: 你需要驾驶一辆卡车行驶 l 单位距离.最开始的时候,卡车上有 p 单位的汽油.卡车每开 1 单位距离需要消费 1 单位的汽油.如果在途中汽车上的汽油耗尽,卡车就无法继续前行,因而无法到达终点.在途中一共有 n 个加油站.第 i 个加油站在距离起点 ai 单位距离的地方,最多可以给卡车加 bi 单位汽油.假设卡车的燃料箱的容量是无限大的,无论加多少油都没有问题

纯数据结构Java实现(6/11)(二叉堆&amp;优先队列)

堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). 但是二叉堆,需要满足一些特殊性质: 其一.二叉堆一定是一棵完全二叉树 (完全二叉树可以用数组表示,见下面) 完全二叉树缺失的部分一定是在右下方.(每层一定是从左到右的顺序优先存放) 完全二叉树的结构,可以简单理解成按层安放元素的.(所以数组是不错的底层实现) 其二.父节点一定比子节点大 (针对大顶堆

堆-优先队列

堆-优先队列 前置知识:二叉树. 参考资料 暂无 堆就是优先队列,可以用来解决动态区间查询最值问题. 堆就是一个完全二叉树,可以插入节点,删除根节点(也可以删除特定节点). 为了方便,普通的堆节点 \(i\) 的父亲就是 \([i\div2]\) (\([x]\) 表示不超过 \(x\) 的最大整数). 节点 \(i\) 的左儿子是 \(i\times2\),右儿子是 \(i\times2+1\). 对于一个大顶堆: 每次插入节点的时候,就把节点插在完全二叉树的最后,如果它比它的父亲节点大,就把

bzoj2151: 种树(双向链表+堆)

题目大意:n个数围成一个圈,选了某个数就不能选它相邻的两个数,问选m个数,最大值为多少. 先用堆维护n个数的最大值,每次取出最大值加进答案,选了某个数之后有可能选它相邻的两个比他更优,所以把旁边的两个数删掉,把这次选的数的值改成左边的数+右边的数-这次选的数,如果下次取了这个数相当于不选这个数换成另外两个,选择m次就是取了m个数.一个数的左右两边的数就用双向链表来搞就行了. 代码如下: var n,m,x,i,ans:longint; l,r,heap,pos,a:array[0..200001

堆(优先队列)求huffman WPL

huffman编码中WPL等于没个结点到根结点的距离乘结点权值的总和,但我们也可以用另一种方法求WPL:如果huffman树只有一个结点,则WPL为根结点权值,否则WPL等于除了根结点以外的所有结点的权值之和. 我们可以用优先队列/堆实现这个过程: 1 //用优先队列求huffman编码中的WPL 2 #include <iostream> 3 using std::cin; 4 using std::cout; 5 using std::endl; 6 using std::swap; 7

种树 (堆模拟网络流)

种树 题目描述 cyrcyr今天在种树,他在一条直线上挖了n个坑.这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树.而且由于cyrcyr的树种不够,他至多会种k棵树.假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利. 输入输出格式 输入格式: 第一行,两个正整数n,k. 第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利. 输出格式: 输出1个数,表示cyrcyr种树的最大获利

Running Median POJ - 3784 (对顶堆/优先队列)

For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After each odd-indexed value is read, output the median (middle value) of the elements received so far. Input The first line of input contains a single int

升序堆和降序堆(优先队列) 洛谷1801

1 // 洛谷1801 2 // 一个升序堆,一个降序堆 3 // 降序堆维护序列的前i个最小值 4 // 插如元素的时候,如果x小于降序堆最大值,则替换,并将最大值插入升序堆:否则,直接插入升序堆 5 // 每次输出升序堆的最小值即可 6 7 8 #include <bits/stdc++.h> 9 using namespace std; 10 #define LL long long 11 typedef pair<int,int> pii; 12 const int inf

【BZOJ 2288】 2288: 【POJ Challenge】生日礼物 (贪心+优先队列+双向链表)

2288: [POJ Challenge]生日礼物 Description ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物. 自然地,ftiasch想要知道选择元素之和的最大值.你能帮助她吗? Input 第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分. 第2行, N 个整数 A1, A2, ..., AN (0