【bzoj5102】[POI2018]Prawnicy 堆
阿新 • • 發佈:2017-12-11
bool sdi main size stat 最大 type line 接下來
題目描述
定義一個區間(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; }
【bzoj5102】[POI2018]Prawnicy 堆