题目大意
数轴上有(n)个闭区间([l_1,r_1],[l_2,r_2],ldots,[l_n,r_n]),你要选出(m)个区间,使得存在一个(x),对于每个选出的区间([l_i,r_i])都有(xin[l_i,r_i])。
一个方案的代价是最长区间长度减去最短区间长度。
求最小的代价。
无解输出(-1)。
(mleq nleq 500000)
题解
就是选出(m)个区间,包含同一个点。
如果多选一些区间,那么答案不会变小。
问题转化成选一些区间,使得存在一个点被(m)个区间包含。
把这些区间按长度排序,用线段树维护每个点被包含的次数。
枚举左端点和右端点,查询是否有一个点被包含(m)次。
设(f_i)为选第(i)个区间为最长的区间时最短的区间是哪个。
显然(f_i)是单调递增的
直接用两个指针维护就行了
因为区间端点的范围很大,所以要离散化。
时间复杂度:(O(nlog n))
题解
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
struct section
{
int l,r;
int d;
};
int cmp(section a,section b)
{
return a.d<b.d;
}
namespace seg
{
struct node
{
int l,r,ls,rs,s,t;
};
node a[2000010];
int n;
void build(int &p,int l,int r)
{
p=++n;
a[p].l=l;
a[p].r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build(a[p].ls,l,mid);
build(a[p].rs,mid+1,r);
}
void add(int p,int v)
{
a[p].s+=v;
a[p].t+=v;
}
void push(int p)
{
if(a[p].l!=a[p].r&&a[p].t)
{
add(a[p].ls,a[p].t);
add(a[p].rs,a[p].t);
a[p].t=0;
}
}
void add(int p,int l,int r,int v)
{
if(l<=a[p].l&&r>=a[p].r)
{
add(p,v);
return;
}
int mid=(a[p].l+a[p].r)>>1;
push(p);
if(l<=mid)
add(a[p].ls,l,r,v);
if(r>mid)
add(a[p].rs,l,r,v);
a[p].s=max(a[a[p].ls].s,a[a[p].rs].s);
}
int query(int p,int l,int r)
{
if(l>r)
return 0;
if(l<=a[p].l&&r>=a[p].r)
return a[p].s;
push(p);
int mid=(a[p].l+a[p].r)>>1;
int res=0;
if(l<=mid)
upmax(res,query(a[p].ls,l,r));
if(r>mid)
upmax(res,query(a[p].rs,l,r));
return res;
}
}
using seg::build;
using seg::add;
using seg::query;
section a[500010];
int d[1000010];
int main()
{
// open("bzoj4653");
int n,m;
scanf("%d%d",&n,&m);
int i;
int t=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].d=a[i].r-a[i].l+1;
d[++t]=a[i].l;
d[++t]=a[i].r;
}
sort(d+1,d+t+1);
t=unique(d+1,d+t+1)-d-1;
sort(a+1,a+n+1,cmp);
for(i=1;i<=n;i++)
{
a[i].l=lower_bound(d+1,d+t+1,a[i].l)-d;
a[i].r=lower_bound(d+1,d+t+1,a[i].r)-d;
}
int j=1;
int rt;
build(rt,1,t);
int ans=0x7fffffff;
for(i=1;i<=n;i++)
{
add(rt,a[i].l,a[i].r,1);
while(max(query(rt,a[j].l,a[j].r)-1,max(query(rt,1,a[j].l-1),query(rt,a[j].r+1,t)))>=m)
{
add(rt,a[j].l,a[j].r,-1);
j++;
}
if(query(rt,1,t)>=m)
ans=min(ans,a[i].d-a[j].d);
}
if(ans==0x7fffffff)
ans=-1;
printf("%d
",ans);
return 0;
}