[bzoj4653] [NOI2016]區間
阿新 • • 發佈:2018-12-25
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
Solution
由於答案是最大的區間減最小的區間,而且和順序沒關係,所以可以按區間長度排序。
按順序加入,顯然當有一個點的覆蓋次數大於\(m\)時,就不加了。
然後對於已經加進去的,從小到大刪除,直到覆蓋次數全都小於\(m\)時,最後一個刪掉的和當前加入的最大的區間肯定可以構成一個當前最優的方案。
然後開個線段樹,拿兩個指標指一下,模擬下上面的過程就行了。
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} const int maxn = 5e6+1; struct node { int l,r,len; bool operator < (const node &rhs) const {return len<rhs.len;} }in[maxn<<1]; int a[maxn],b[maxn],n,m,tot,head,tail; #define ls p<<1 #define rs p<<1|1 #define mid ((l+r)>>1) struct Segment_Tree { int tr[maxn],tag[maxn]; void push_tag(int p,int v) {tr[p]+=v,tag[p]+=v;} void update(int p) {tr[p]=max(tr[ls],tr[rs]);} void pushdown(int p) { if(tag[p]) push_tag(ls,tag[p]),push_tag(rs,tag[p]),tag[p]=0; } void modify(int p,int l,int r,int x,int y,int v) { if(x<=l&&r<=y) return push_tag(p,v),void(); pushdown(p); if(x<=mid) modify(ls,l,mid,x,y,v); if(y>mid) modify(rs,mid+1,r,x,y,v); update(p); } }SGT; #undef ls #undef rs #undef mid int main() { read(n),read(m); for(int i=1;i<=n;i++) read(in[i].l),read(in[i].r),in[i].len=in[i].r-in[i].l; sort(in+1,in+n+1); for(int i=1;i<=n;i++) a[++tot]=in[i].l,a[++tot]=in[i].r; sort(a+1,a+tot+1);int M=unique(a+1,a+tot+1)-a-1; for(int i=1;i<=n;i++) { in[i].l=lower_bound(a+1,a+M+1,in[i].l)-a; in[i].r=lower_bound(a+1,a+M+1,in[i].r)-a; } int ans=1e9; while(tail<n) { while(tail<n&&SGT.tr[1]<m) tail++,SGT.modify(1,1,n*2,in[tail].l,in[tail].r,1); if(SGT.tr[1]<m) break; while(head<=tail&&SGT.tr[1]>=m) head++,SGT.modify(1,1,n*2,in[head].l,in[head].r,-1); ans=min(ans,in[tail].len-in[head].len); } if(ans!=1e9) write(ans);else puts("-1"); return 0; }