1. 程式人生 > >BZOJ 4653: [Noi2016]區間 線段樹

BZOJ 4653: [Noi2016]區間 線段樹

Description

在數軸上有 n個閉區間 [l1,r1],[l2,r2],…,[ln,rn]。現在要從中選出 m 個區間,使得這 m個區間共同包含至少一個位置。換句話說,就是使得存在一個 x,使得對於每一個被選中的區間 [li,ri],都有 li≤x≤ri。
對於一個合法的選取方案,它的花費為被選中的最長區間長度減去被選中的最短區間長度。區間 [li,ri] 的長度定義為 ri−li,即等於它的右端點的值減去左端點的值。
求所有合法方案中最小的花費。如果不存在合法的方案,輸出 −1。

Input

第一行包含兩個正整數 n,m用空格隔開,意義如上文所述。保證 1≤m≤n
接下來 n行,每行表示一個區間,包含用空格隔開的兩個整數 li 和 ri 為該區間的左右端點。
N<=500000,M<=200000,0≤li≤ri≤10^9

Output

只有一行,包含一個正整數,即最小花費。

Sample Input

6 3

3 5

1 2

3 4

2 2

1 5

1 4

Sample Output

2

題解

首先我們將所有區間按照長度排序,然後我們依次掃描每個區間,用線段樹找到它第一次有點覆蓋次數超過k的另一個區間,更新一下答案,因為左端點遞增時右端點也一定遞增,所以維護兩個指標掃一下即可。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string> #include<algorithm> #include<ctime> #include<cmath> using namespace std; struct xianduan { int l,r,maxx,lazy; void add(int val) { maxx+=val; lazy+=val; } }a[5000000]; void make_tree(int o,int l,int r) { a[o].l=l; a[o].r=r; a[o].maxx=0
; a[o].lazy=0; if(l==r) return; int mid=l+r>>1; make_tree(2*o,l,mid); make_tree(2*o+1,mid+1,r); } void push_down(int o) { if(a[o].l==a[o].r) return; if(!a[o].lazy) return; a[2*o].add(a[o].lazy); a[2*o+1].add(a[o].lazy); a[o].lazy=0; } void change(int o,int l,int r,int d) { if(a[o].r<l || a[o].l>r) return; push_down(o); if(a[o].l>=l && a[o].r<=r) { a[o].add(d); return; } change(2*o,l,r,d); change(2*o+1,l,r,d); a[o].maxx=max(a[2*o].maxx,a[2*o+1].maxx); } struct interval { int l,r,val; bool operator < (interval b) const { return val<b.val; } }q[600000]; int dd[1100000]; int top=0; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].val=q[i].r-q[i].l+1,dd[++top]=q[i].l,dd[++top]=q[i].r; sort(dd+1,dd+1+top); top=unique(dd+1,dd+1+top)-dd-1; for(int i=1;i<=n;i++) q[i].l=lower_bound(dd+1,dd+1+top,q[i].l)-dd,q[i].r=lower_bound(dd+1,dd+1+top,q[i].r)-dd; sort(q+1,q+1+n); int r=1; int ans=2147483647; make_tree(1,1,top); for(int i=1;i<=n;i++) { while(a[1].maxx<m && r<=n) { change(1,q[r].l,q[r].r,1); r++; } if(a[1].maxx<m) break; ans=min(ans,q[r-1].val-q[i].val); change(1,q[i].l,q[i].r,-1); } if(ans==2147483647) cout<<-1; else cout<<ans<<endl; return 0; }