题目描述
在数轴上有 个闭区间 。现在要从中选出 个区间,使得这 个区间共同包含至少一个位置。换句话说,就是使得存在一个 ,使得对于每一个被选中的区间 ,都有 。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 的长度定义为 ,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 。
输入输出格式
输入格式:
第一行包含两个正整数
用空格隔开,意义如上文所述。保证
接下来 行,每行表示一个区间,包含用空格隔开的两个整数 和 为该区间的左右端点。
输出格式:
只有一行,包含一个正整数,即最小花费。
输入输出样例
输入样例#1:
6 3
3 5
1 2
3 4
2 2
1 5
1 4
输出样例#1:
2
说明
分析:
首先我们给区间按长度排序。然后维护两个指针l,r,表示当前选择了[l,r]的区间。每次插入一个区间,然后查询是否有一个点出现超过
次,那么这个状态就可以更新答案。然后我们让左指针右移, 直到没有任何一个点出现超过
次,中间这些状态也可以更新答案。
因为题目要求是大小的差最小,为了更优,我们肯定会把
之间全部区间插入进去,判断是否有一个点出现超过
次。正确性显然。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
const int maxn=1e6+7;
using namespace std;
int n,m,ans,x,y;
struct tree{
int maxx;
int lazy;
}t[maxn*4];
struct rec{
int l,r,size;
}a[maxn];
struct node{
int x,num,k;
}b[maxn];
bool cmp1(node x,node y)
{
return x.x<y.x;
}
bool cmp2(rec x,rec y)
{
return x.size<y.size;
}
void ins(int p,int l,int r,int x,int y,int k)
{
if ((l==x) && (r==y))
{
t[p].maxx+=k;
t[p].lazy+=k;
return;
}
int mid=(l+r)/2;
if (t[p].lazy)
{
t[p*2].maxx+=t[p].lazy;
t[p*2].lazy+=t[p].lazy;
t[p*2+1].maxx+=t[p].lazy;
t[p*2+1].lazy+=t[p].lazy;
t[p].lazy=0;
}
if (y<=mid) ins(p*2,l,mid,x,y,k);
else if (x>mid) ins(p*2+1,mid+1,r,x,y,k);
else
{
ins(p*2,l,mid,x,mid,k);
ins(p*2+1,mid+1,r,mid+1,y,k);
}
t[p].maxx=max(t[p*2].maxx,t[p*2+1].maxx);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
b[i]=(node){x,i,0};
b[i+n]=(node){y,i,1};
a[i].size=y-x+1;
}
sort(b+1,b+2*n+1,cmp1);
int cnt=0;
for (int i=1;i<=2*n;i++)
{
if ((b[i].x!=b[i-1].x) || (i==1)) cnt++;
if (!b[i].k) a[b[i].num].l=cnt;
a[b[i].num].r=cnt;
}
sort(a+1,a+n+1,cmp2);
int pre=1;
int ans=0x3f3f3f3f;
for (int i=1;i<=n;i++)
{
ins(1,1,cnt,a[i].l,a[i].r,1);
while (t[1].maxx>=m)
{
ans=min(ans,a[i].size-a[pre].size);
ins(1,1,cnt,a[pre].l,a[pre].r,-1);
pre++;
}
}
if (ans==0x3f3f3f3f) printf("-1");
else printf("%d",ans);
}