Description
给出数轴上的(n(nleq5 imes10^5))个闭区间,从中选出(m(mleq2 imes10^5))个,并且它们的交集不为空。一个合法方案的代价为所选区间中的最长长度减去最短长度,求最小代价。
Solution
将区间按长度由小到大排序。每次钦定区间(i)为最短区间,然后寻找(jgeq i)使得存在至少一个数被区间(i..j)中的(m)个覆盖,这可以用线段树实现。因为(j)是不退的,所以循环(i=1..n),每次向后寻找(j)即可。
时间复杂度(O(nlogn))。
Code
//[NOI2016]区间
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
inline char gc()
{
static char now[1<<16],*s,*t;
if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
return *s++;
}
inline int read()
{
int x=0; char ch=gc();
while(ch<'0'||'9'<ch) ch=gc();
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x;
}
int const N=1e6+10;
int n,m; int n0,map[N];
struct range{int L,R;} r[N>>1];
bool cmpRng(range x,range y) {return x.R-x.L<y.R-y.L;}
#define Ls (p<<1)
#define Rs ((p<<1)|1)
int rt; int maxV[N<<2],tag[N<<2];
int L,R;
void update(int p) {maxV[p]=max(maxV[Ls],maxV[Rs]);}
void add(int p,int x) {maxV[p]+=x,tag[p]+=x;}
void pushdw(int p) {if(tag[p]) add(Ls,tag[p]),add(Rs,tag[p]),tag[p]=0;}
void ins(int p,int L0,int R0,int x)
{
if(L<=L0&&R0<=R) {add(p,x); return;}
pushdw(p);
int mid=L0+R0>>1;
if(L<=mid) ins(Ls,L0,mid,x);
if(mid<R) ins(Rs,mid+1,R0,x);
update(p);
}
int query(int p,int L0,int R0)
{
if(L<=L0&&R0<=R) return maxV[p];
pushdw(p);
int mid=L0+R0>>1; int res=0;
if(L<=mid) res=max(res,query(Ls,L0,mid));
if(mid<R) res=max(res,query(Rs,mid+1,R0));
return res;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++) map[i*2-1]=r[i].L=read(),map[i*2]=r[i].R=read();
sort(r+1,r+n+1,cmpRng);
sort(map+1,map+n+n+1); n0=unique(map+1,map+n+n+1)-map-1;
for(int i=1;i<=n;i++) r[i].L=lower_bound(map+1,map+n0+1,r[i].L)-map;
for(int i=1;i<=n;i++) r[i].R=lower_bound(map+1,map+n0+1,r[i].R)-map;
int ans=2e9; rt=1;
for(int i=1,j=0;i<=n;i++)
{
while(true)
{
if(maxV[rt]>=m) break;
if(++j>n) break;
L=r[j].L,R=r[j].R,ins(rt,1,n0,1);
}
if(j>n) break;
ans=min(ans,(map[r[j].R]-map[r[j].L])-(map[r[i].R]-map[r[i].L]));
L=r[i].L,R=r[i].R; ins(rt,1,n0,-1);
}
if(ans==2e9) puts("-1");
else printf("%d
",ans);
return 0;
}
P.S.
我菜死了...其实很简单的,也做过类似的题