[BZOJ2288&BZOJ1150]一类堆+链表+贪心问题
今天我们来介绍一系列比较经典的堆+链表问题.这类问题的特点是用堆选取最优解,并且通过一些加减操作来实现"反悔".
在看题之前,我们先来介绍一个神器:手写堆.
手写堆的一大好处就是可以可以访问,或者删除堆中的某个特定元素.
手写堆其实就是在模拟二叉堆的比较大小过程,比如:
inline void up(int id)
{
if(id==)return;
if(h[id>>]<h[id])
swap(h[id>>],h[id]),up(id>>);
}
inline void down(int id)
{
id<<=;if(id>top)return;
if(id<top&&h[id^]>h[id])id^=;
if(h[id>>]<h[id])
swap(h[id>>],h[id]),down(id);
}
这样我们已经可以查找最值了.如果我们想删除某个值,就直接把它的权值设为无穷大/小,再调用down函数.
如果我们还想支持查询某个标号对应的值(下面两个题都会用到)
可以多加一个match数组记录编号.当然,这里的h既要记录编号又要记录权值.
完整的像这样,当然,读者可以结合自己的风格打出自己的手写堆:
int match[N],top;
struct node
{
int val,pos;
node(int a=,int b=){val=a,pos=b;}
}h[N];
inline void up(int i)
{
while(i>&&h[i].val<h[i>>].val)
match[h[i>>].pos]=i,swap(h[i>>],h[i]),i>>=;
match[h[i].pos]=i;
}
inline void down(int i)
{
int to;
while((i<<)<=top)
{
to=(i<<);if(to<top&&h[to+].val<h[to].val)++to;
if(h[to].val<h[i].val)
match[h[to].pos]=i,swap(h[i],h[to]),i=to;
else break;
}
match[h[i].pos]=i;
}
inline void push(int val,int pos)
{h[++top]=node(val,pos);up(top);}
inline void pop(int i)
{h[i].val=inf;down(i);}
拿到了我们的强力武器,话不多说,我们先看一道题:
1150: [CTSC2007]数据备份Backup
Time Limit: 10 Sec Memory Limit: 162 MB
Description

Input
Output
输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。
Sample Input
1
3
4
6
12
Sample Output
然后,如果我们又选到了节点i,这时候再给ans加上它的val,我们实质上选了val[i-1]和val[i+1],

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=,inf=0x7fffffff;
int n,m,s[N],d[N],cnt,top;
int match[N];
struct node
{
int val,pos;
node(int a=,int b=){val=a,pos=b;}
}h[N];
inline void up(int i)
{
while(i>&&h[i].val<h[i>>].val)
match[h[i>>].pos]=i,swap(h[i>>],h[i]),i>>=;
match[h[i].pos]=i;
}
inline void down(int i)
{
int to;
while((i<<)<=top)
{
to=(i<<);if(to<top&&h[to+].val<h[to].val)++to;
if(h[to].val<h[i].val)
match[h[to].pos]=i,swap(h[i],h[to]),i=to;
else break;
}
match[h[i].pos]=i;
}
inline void push(int val,int pos)
{h[++top]=node(val,pos);up(top);}
inline void pop(int i)
{h[i].val=inf;down(i);}
int pre[N],nxt[N];
int main()
{
register int i,j,k;
scanf("%d%d",&n,&m);
for(i=;i<=n;++i)scanf("%d",&s[i]);
for(i=;i<n;++i)d[i]=s[i+]-s[i],push(d[i],i);
for(i=;i<n;++i)pre[i]=i-,nxt[i]=i+;
nxt[n-]=;
node x;int l,r,ans=;
for(i=;i<=m;++i)
{
x=h[];ans+=x.val;
l=pre[x.pos],r=nxt[x.pos];
if(!l) pop(),pop(match[r]),pre[nxt[r]]=;
else if(!r) pop(),pop(match[l]),nxt[pre[l]]=;
else
h[].val=h[match[l]].val+h[match[r]].val-h[].val,
pre[x.pos]=pre[l],nxt[pre[l]]=x.pos,
nxt[x.pos]=nxt[r],pre[nxt[r]]=x.pos,
pop(match[l]),pop(match[r]),down();
}
printf("%d\n",ans);
}
下面我们再来看另外一道题,套路是相似的,但是更加有挑战性:
2288: 【POJ Challenge】生日礼物
Time Limit: 10 Sec Memory Limit: 128 MB
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 ≤ |Ai| ≤ 104), 序列。
Output
一个整数,最大的和。
Sample Input
2 -3 2 -1 2
Sample Output
[BZOJ2288&BZOJ1150]一类堆+链表+贪心问题的更多相关文章
- BZOJ 2288: 【POJ Challenge】生日礼物 堆&&链表
就是堆+链表,十分像 数据备份 对吧? 把相邻的正数和相邻的负数合并成一整个正数块和负数块,最后只剩一些交替相间的正块与负块了吧? 显然,正块的个数<=m时,全部选走就获得了最大权值,否则我们可 ...
- [USACO12FEB]牛券Cow Coupons(堆,贪心)
[USACO12FEB]牛券Cow Coupons(堆,贪心) 题目描述 Farmer John needs new cows! There are N cows for sale (1 <= ...
- [bzoj2288][pojChallenge]生日礼物【贪心+堆+链表】
题目描述 ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, -, AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物. 自然地,ftiasch想要知 ...
- BZOJ_2151_种树_贪心+堆+链表
BZOJ_2151_种树_贪心+堆 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编 ...
- BZOJ1150 [CTSC2007]数据备份Backup 【堆 + 链表】
题目 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的 ...
- BZOJ1150[CTSC2007]数据备份Backup——模拟费用流+堆+链表
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游 ...
- [luogu3620][APIO/CTSC 2007]数据备份【贪心+堆+链表】
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...
- BZOJ2151 种树(贪心+堆+链表/wqs二分+动态规划)
dp容易想到,但没法进一步优化了. 考虑贪心,每次选出价值最大的物品.但这显然是不对的因为会影响其他物品的选择. 于是考虑加上反悔操作.每次选出一个物品后,将其相邻两物品删除,再将原物品价值变为相邻两 ...
- BZOJ2288 【POJ Challenge】生日礼物 【堆 + 链表】
题目 ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物. 自然地,ftiasch想要知 ...
随机推荐
- 利用自定义 ORM 下使用 flask-login 做登录校验使用笔记
1. 安装: pip install flask_login 2. 使用: 注册应用 import os from flask_login import LoginManager, current_u ...
- Android Service(下)
阅读本文需要先阅读Android Service(上) 一 为什么需要bindService() 绑定服务就是为了和服务进行通讯 可以调用服务里面的方法 二 bindService()调用服务里面方法 ...
- 使用Amplify Shader Editor优化特效Shader
ASE相对于Shader Forge生成的代码更加干净, 用于制作特效的再合适不过,以下是使用ASE优化一个SF制作特效的经过: ## 分析美术用SF制作的Shader 懒得装SF, 直接分析代码可知 ...
- 通过XML文件实现人物之间的对话
一.建立一个XML文档,放在项目中Assert/Resources/XML文件下 XML的内容如下: <?xml version="1.0" encoding="u ...
- kubeadm 线上集群部署(二) K8S Master集群安装以及工作节点的部署
PS:所有机器主机名请提前设置好 在上一篇,ETCD集群我们已经搭建成功了,下面我们需要搭建master相关组件,apiverser需要与etcd通信并操作 1.配置证书 将etcd证书上传到mast ...
- 从零开始的Python学习Episode 18——面向对象(1)
类与对象 类即类别.种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体. 类的定义 class 类名: 属性1 属性2 def 方法(self,ar ...
- Python入门学习系列——Python文件和异常
从文件中读取数据 首先准备一个文本文件,文件中存储着普通文本数据.读取文件需要调用open()和read()函数. 读取整个文件 代码示例: with open('pi_digits.txt') as ...
- 兼容所有浏览器的旋转效果-IE滤镜Matrix和CSS3transform
在现代浏览器中使用CSS3的transform样式即可轻松搞定,但是对于国内IE浏览器(特别是7,8)还占有较大份额的情况下,兼容性还是必须要考虑的,所以也特意记录下IE旋转滤镜的使用. 在IE下的旋 ...
- 使用sass与compass合并雪碧图(一)
雪碧图就是很多张小图片合并成一张大图片,以减少HTTP请求,从而提升加载速度.有很多软件可以合并雪碧图,但通常不太容易维护,使用compass生成雪碧图应该算是非常方便的方法了,可以轻松的生成雪碧图, ...
- Alpha版本BUG BASH
在本次软件开发的第一轮迭代中,我们团队遇到了很多问题.首先是和学长联系不上导致拿到项目前一版本的代码的时间延后了一个星期. 拿到代码后发现由于安装环境的问题代码无法移植.在这一阶段我们就耗费了大量的时 ...