【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;
}

 

 

posted @ 2017-12-11 20:38  GXZlegend  阅读(484)  评论(0编辑  收藏  举报