题目: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
题解:
这道题说实话是算比较基础的题目,,我居然只能想到50+的水法。。看来我线段树还不是很熟。。一开始连题目都读错了,差点没看懂样例。
其实很简单。。
因为l[i],r[i]<=10^9,而最多只有500000个区间,所以我们可以缩点,并不会对答案造成影响。
hash缩完点以后,把用线段树把每一段给出的区间的覆盖次数+1,然后如果有答案的话树根的存储值肯定>=m,此时我们只要把之前的区间一个个减去,直到符合m次覆盖为止,然后更新答案。
不懂缩点的可以在下面留言告诉我,最近常常混迹blog。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAXN 500010
#define MAXM 1010
#define inf 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct node{
int l;
int r;
int len;
friend bool operator <(node x,node y){
return x.len<y.len;
}
};
int n,m;
int tot[MAXN*2],tot1,mx;
node a[MAXN];
map<int,int>h;
int ch[MAXN<<3],tr[MAXN<<3];
int ans=inf*2;
inline void add(int x,int y){
ch[x]+=y;
tr[x]+=y;
}
inline void make(int x)
{
if (ch[x])
{
add(x<<1,ch[x]);
add(x<<1|1,ch[x]);
ch[x]=0;
}
}
void change(int z,int x,int y,int l,int r,int cv)
{
if (x==l&&y==r){
add(z,cv);
return ;
}
make(z);
int mid=x+y>>1;
if (r<=mid) change(z<<1,x,mid,l,r,cv);
else if (l>mid) change(z<<1|1,mid+1,y,l,r,cv);
else{
change(z<<1,x,mid,l,mid,cv);
change(z<<1|1,mid+1,y,mid+1,r,cv);
}
tr[z]=max(tr[z<<1],tr[z<<1|1]);
}
int main(){
int i;
scanf("%d%d",&n,&m);
if (!m)
{
printf("%d\n",0);
return 0;
}
for (i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].len=a[i].r-a[i].l;
tot[++tot1]=a[i].l;
tot[++tot1]=a[i].r;
}
sort(tot+1,tot+tot1+1);
tot[0]=-inf;
for (i=1;i<=tot1;i++)
{
if (tot[i]!=tot[i-1])
h[tot[i]]=++mx;
}
for (i=1;i<=n;i++)
{
a[i].l=h[a[i].l];
a[i].r=h[a[i].r];
}
sort(a+1,a+1+n);
int k=1;
for (i=1;i<=n;i++)
{
change(1,1,mx,a[i].l,a[i].r,1);
while (tr[1]>=m)
{
ans=min(ans,a[i].len-a[k].len);
change(1,1,mx,a[k].l,a[k].r,-1);
k++;
}
}
if(ans==inf*2){
ans=-1;
}
printf("%d\n",ans);
return 0;
}
好久没打c++了,打起来有点累。。