BZOJ 4653: [Noi2016]區間 線段樹
阿新 • • 發佈:2019-02-17
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;
}