[NOI2016]区间
Description:
在数轴上有\(N\) 个闭区间 \([l_1,r_1],[l_2,r_2],...,[l_n,r_n]\) 。现在要从中选出\(M\) 个区间,使得这\(M\) 个区间共同包含至少一个位置。换句话说,就是使得存在一个 \(x\) ,使得对于每一个被选中的区间\([l_i,r_i]\) ,都有 \(l_i≤x≤r_i\) 。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间\([l_i,r_i]\) 的长度定义为\(r_i-l_i\) ,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出\(-1\)
Hint:
\(n\le 5*10^5\)
Solution:
水题,观察到\(Ans=min\{max_{len}-min_{len}(存在一个x覆盖>=m)\}\)
这种形式的式子就一定是双指针了
所以按长度排序,双指针维护一下条件,线段树判一下\(>=m\)就行了
数组开大点.....
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=4e6+5;
ll n,m,cnt,hd[mxn];
inline ll read() {
char c=getchar(); ll x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(ll &x,ll y) {if(x<y) x=y;}
inline void chkmin(ll &x,ll y) {if(x>y) x=y;}
struct ed {
ll to,nxt;
}t[mxn<<1];
inline void add(ll u,ll v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
ll inf=2e9;
ll tot,bd,ans=inf,b[mxn];
ll tr[mxn<<2],tag[mxn<<2];
struct I {
ll l,r,len;
}q[mxn];
ll cmp(I x,I y) {
return x.len<y.len;
}
void push_up(ll p) {
tr[p]=max(tr[ls],tr[rs]);
}
void push_down(ll p,ll l,ll r) {
if(tag[p]) {
ll mid=(l+r)>>1;
tag[ls]+=tag[p]; tag[rs]+=tag[p];
tr[ls]+=tag[p];
tr[rs]+=tag[p];
tag[p]=0;
}
}
void update(ll l,ll r,ll ql,ll qr,ll x,ll p) {
if(ql<=l&&r<=qr) {
tag[p]+=x;
tr[p]+=x;
return ;
}
ll mid=(l+r)>>1; push_down(p,l,r);
if(ql<=mid) update(l,mid,ql,qr,x,ls);
if(qr>mid) update(mid+1,r,ql,qr,x,rs);
push_up(p);
}
int main()
{
n=read(); m=read(); ll l,r,len;
for(ll i=1;i<=n;++i) {
l=read(),r=read(),len=r-l;
q[i]=(I){l,r,len}; b[++tot]=l,b[++tot]=r;
}
sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1;
for(ll i=1;i<=n;++i)
q[i].l=lower_bound(b+1,b+tot+1,q[i].l)-b,
q[i].r=lower_bound(b+1,b+tot+1,q[i].r)-b,chkmax(bd,q[i].r);
sort(q+1,q+n+1,cmp); ll pos=1;
for(ll i=1;i<=n;++i) {
update(1,bd,q[i].l,q[i].r,1,1);
if(tr[1]<m) continue ;
else while(tr[1]>=m&&pos<=i) {
chkmin(ans,q[i].len-q[pos].len);
update(1,bd,q[pos].l,q[pos].r,-1,1); ++pos;
}
}
if(ans!=inf) printf("%lld",ans);
else puts("-1");
return 0;
}