时空限制 1000ms-3000ms / 256MB
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
只有一行,包含一个正整数,即最小花费。
题目分析
先将给定区间按区间长度升序排序
像维护队列一样维护区间
初始队列内只有第一个区间,之后不断按顺序从队尾加入区间,并记录每个点被覆盖的次数
若发现某个点被覆盖次数>=m,此时队尾后面的区间一定不能与队头区间组成更优解
所以不断用队尾区间与队头区间更新答案,将队头区间弹出
直到所有点被覆盖次数
维护区间加和区间最值的数据结构很容易想到线段树
由于每个区间都只会在入队出队时修改一次,所以总复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
注意区间需要离散化
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const lt inf=2e9;
const int maxn=2000010;
int n,m;
int mx[maxn<<2],add[maxn<<2];
struct node{int ll,rr;lt d;}rem[maxn];
int a[maxn],pos[maxn],cnt;
bool cmp(node x,node y){return x.d<y.d;}
void push(int s,int t,int p,int mid)
{
if(!add[p]) return;
add[p<<1]+=add[p]; add[p<<1|1]+=add[p];
mx[p<<1]+=add[p]; mx[p<<1|1]+=add[p];
add[p]=0;
}
void update(int ll,int rr,int s,int t,int p,int val)
{
if(ll<=s&&t<=rr){ mx[p]+=val; add[p]+=val; return;}
int mid=s+t>>1;
push(s,t,p,mid);
if(ll<=mid) update(ll,rr,s,mid,p<<1,val);
if(rr>mid) update(ll,rr,mid+1,t,p<<1|1,val);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
{
int ll=read(),rr=read();
rem[i].ll=a[++cnt]=ll;
rem[i].rr=a[++cnt]=rr;
rem[i].d=rr-ll;
}
sort(a+1,a+1+cnt); cnt=0;
for(int i=1;i<=n*2;++i)
if(i==1||a[i]!=a[i-1])
pos[++cnt]=a[i];
for(int i=1;i<=n;++i)
{
rem[i].ll=lower_bound(pos+1,pos+1+cnt,rem[i].ll)-pos;
rem[i].rr=lower_bound(pos+1,pos+1+cnt,rem[i].rr)-pos;
}
lt ans=inf; int L=1,R=1;
sort(rem+1,rem+1+n,cmp);
while(R<=n)
{
update(rem[R].ll,rem[R].rr,1,cnt,1,1);
while(mx[1]>=m){
ans=min(ans,rem[R].d-rem[L].d);
update(rem[L].ll,rem[L].rr,1,cnt,1,-1);
L++;
}
R++;
}
if(ans==inf) printf("-1");
else printf("%lld",ans);
return 0;
}