【bzoj5102】[POI2018]Prawnicy 堆

题目描述

定义一个区间(l,r)的长度为r-l,空区间的长度为0。

给定数轴上n个区间,请选择其中恰好k个区间,使得交集的长度最大。

输入

第一行包含两个正整数n,k(1<=k<=n<=1000000),表示区间的数量。

接下来n行,每行两个正整数l,r(1<=l<r<=10^9),依次表示每个区间。

输出

第一行输出一个整数,即最大长度。

第二行输出k个正整数,依次表示选择的是输入文件中的第几个区间。

若有多组最优解,输出任意一组。

样例输入

6 3
3 8
4 12
2 6
1 10
5 9
11 12

样例输出

4
1 2 4



题解

考虑将所有区间按照左端点位置从小到大排序(套路),然后考虑答案中左端点最靠右的那个区间。

那么答案区间的左端点就是这个区间的左端点,右端点是选择的所有区间中的最小值。枚举左端点最靠右的区间,想让区间长度越大,就要让右端点越靠右。因此右端点是min(所有前面的区间中第k-1小的,当前区间右端点)。

由于k是固定的,因此可以在枚举过程中使用堆来维护这些取值,然后统计答案。

题目还要输出方案,因此还需要维护出答案的位置,再重新计算一遍即可。

时间复杂度 $O(n\log n)$

#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
struct data
{
	int l , r , id;
	bool operator<(const data &a)const {return r > a.r;}
}a[1000010];
priority_queue<data> q;
bool cmp(data a , data b)
{
	return a.l < b.l;
}
inline char nc()
{
	static char buf[100000] , *p1 , *p2;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
	int ret = 0; char ch = nc();
	while(!isdigit(ch)) ch = nc();
	while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ ‘0‘) , ch = nc();
	return ret;
}
int main()
{
	int n = read() , k = read() , i , ans = -1 << 30 , pos;
	for(i = 1 ; i <= n ; i ++ ) a[i].l = read() , a[i].r = read() , a[i].id = i;
	sort(a + 1 , a + n + 1 , cmp);
	for(i = 1 ; i < k ; i ++ ) q.push(a[i]);
	for(i = k ; i <= n ; i ++ )
	{
		q.push(a[i]);
		if(q.top().r - a[i].l > ans) ans = q.top().r - a[i].l , pos = i;
		q.pop();
	}
	printf("%d\n" , ans);
	while(!q.empty()) q.pop();
	for(i = 1 ; i <= pos ; i ++ ) q.push(a[i]);
	for(i = k ; i < pos ; i ++ ) q.pop();
	while(!q.empty()) printf("%d " , q.top().id) , q.pop();
	return 0;
}
时间: 2024-10-10 12:26:59

【bzoj5102】[POI2018]Prawnicy 堆的相关文章

[POI2018]Prawnicy

题目大意: 有$n(n\le10^6)$个线段,每个线段覆盖的范围是$[l_i,r_i]$,要求从中选取$k(k\le10^6)$个线段使得这些线段覆盖范围的交集最大,求最大交集及任意一种方案. 思路: 对左端点排序,用堆维护右端点即可. 1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 #include<sys/mman.h> 6 #i

JavaScript栈和堆内存,作用域

1.栈 stack"和"堆 heap": 简单的来讲,stack上分配的内存系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里.stack一般是静态分配内存,heap上一般是动态分配内存. 2.基本类型和引用类型: 基本类型:存放在栈内存中的简单数据段.数据大小确定,内存空间大小可以分配. 引用类型:存放在堆内存中的对象,变量中实际保存的是一个指针,这个指针指向另一个位置.每个空间大小不一样,要根据情况开进行特定的分配. 详见<Javas

堆内存、栈内存分析图

堆内存保存的是真正的数据,简单说是对象的属性信息 栈内存保存的是对内存的地址,简单理解对象名称

JVM学习(2)——技术文章里常说的堆,栈,堆栈到底是什么,从os的角度总结--转载http://www.cnblogs.com/kubixuesheng/p/5202561.html

转载自---http://www.cnblogs.com/kubixuesheng/p/5202561.html 俗话说,自己写的代码,6个月后也是别人的代码--复习!复习!复习!涉及到的知识点总结如下: 堆栈是栈 JVM栈和本地方法栈划分 Java中的堆,栈和c/c++中的堆,栈 数据结构层面的堆,栈 os层面的堆,栈 JVM的堆,栈和os如何对应 为啥方法的调用需要栈 属于月经问题了,正好碰上有人问我这类比较基础的知识,无奈我自觉回答不是有效果,现在深入浅出的总结下: 前一篇文章总结了:JV

数据结构中的堆

一:堆排序      堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树.大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i].在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶.下面附上简单C#简单实现: using System; using System.Collections.Generi

堆和栈 的区别

栈:自动回收 堆:1.内存地址  2.初始化默认值 3.垃圾回收机制 int a  = 5;  在栈中. int[] b =null;  此时null 代表 不指向任何堆. int [] c =new int[5];在堆中开辟一块空间.此时 c指一块内存地址. =======================学习黑马java视频学习的,讲的很生动,又缕了一遍.一会该练吉他了 ====以下为网上找的资料 1.在看例子之前,确保你理解以下几个术语: 栈:由JVM分配区域,用于保存线程执行的动作和数据引

桥堆的参数选择以及滤波电容的选择

1.桥堆的参数选择: 2.滤波电容选择:对于整流电压的输出电压大小,大家一定不陌生.很多人会说,输出平均值全波0.9倍,半波0.45倍的交流有效.但是在设计中,我们常常发现一个事实,例如在半波整流后,输出电压得到的不止0.45倍,9V交流整流后可能有11-12V.之前我一直很困惑,是我记错了计算倍数吗?翻了很多书籍,公式当然是没错的.那到底怎么回事? 可能之前我们在学校学这个方面知识点的时候太过注重整流电路,而忽略了脉动比的概念,所以造成我们现在很多人对这一简单的知识不是很清晰.其实这里是由于整

【堆】

看上去好像很简单的样子··然后折磨了我好久···· 主要是没仔细弄明白. 堆分为最小堆和最大堆,以二叉树的形式存在,最小堆即根节点为整个树的最小值,最大堆则是根节点为最大值. 建堆(以最大堆为例): 首先数据以数组形式存储(int a[]或vector<int> a),若二叉树的根节点从0开始计数,则节点 i 的左右子节点的下标分别为2 * i + 1和 2 * i + 2(忘了怎么算可以画一棵树,就知道了). void heap_down(int a[], int id, int numsS

《ACM/ICPC 算法训练教程》读书笔记一之数据结构(堆)

书籍简评:<ACM/ICPC 算法训练教程>这本书是余立功主编的,代码来自南京理工大学ACM集训队代码库,所以小编看过之后发现确实很实用,适合集训的时候刷题啊~~,当时是听了集训队final的意见买的,感觉还是不错滴. 相对于其他ACM书籍来说,当然如书名所言,这是一本算法训练书,有着大量的算法实战题目和代码,尽管小编还是发现了些许错误= =,有部分注释的语序习惯也有点不太合我的胃口.实战题目较多是比较水的题,但也正因此才能帮助不少新手入门,个人认为还是一本不错的算法书,当然自学还是需要下不少