bzoj 4653: [Noi2016]区间
题目大意:
给定n个闭区间,从中选出m个区间且选出的区间长度极差最小. n <= 500000
题解:
使用双变量法:我们枚举l,r表示插入所有长度在[l,r]之间的线段,
用线段树维护一下每个点被多少条线段覆盖,当mx >= m时用r-l更新ans即可
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 500010;
int T[maxn<<3],lazy[maxn<<3];
inline void pushdown(int rt){
if(rt == 0 || lazy[rt] == 0) return;
T[rt<<1] += lazy[rt];T[rt<<1|1] += lazy[rt];
lazy[rt<<1] += lazy[rt];lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
void modify(int rt,int l,int r,int L,int R,int d){
if(L <= l && r <= R){
T[rt] += d;lazy[rt] += d;
return ;
}
int mid = l+r >> 1;pushdown(rt);
if(L <= mid) modify(rt<<1,l,mid,L,R,d);
if(R > mid) modify(rt<<1|1,mid+1,r,L,R,d);
T[rt] = max(T[rt<<1],T[rt<<1|1]);
}
struct num{
int l,r,val;
bool friend operator < (const num &a,const num&b){
return a.val < b.val;
}
}a[maxn];
int b[maxn<<1];
int main(){
int n,m,cnt=0;read(n);read(m);
for(int i=1;i<=n;++i){
read(a[i].l);read(a[i].r);
b[++cnt] = a[i].l;b[++cnt] = a[i].r;
if(a[i].l > a[i].r) swap(a[i].l,a[i].r);
a[i].val = a[i].r - a[i].l;
}
sort(a+1,a+n+1);sort(b+1,b+cnt+1);
for(int i=1;i<=n;++i){
a[i].l = lower_bound(b+1,b+cnt+1,a[i].l) - b;
a[i].r = lower_bound(b+1,b+cnt+1,a[i].r) - b;
}
int ans = 0x3f3f3f3f;
int l = 1,r = 1;
modify(1,1,n<<1,a[1].l,a[1].r,1);
while(l <= n && r <= n){
while(T[1] < m && r < n) modify(1,1,n<<1,a[r+1].l,a[r+1].r,1),++r;
if(T[1] >= m && l <= r) ans = min(ans,a[r].val-a[l].val);
else break;
modify(1,1,n<<1,a[l].l,a[l].r,-1);++ l;
}
printf("%d\n",ans == 0x3f3f3f3f ? -1 : ans);
return 0;
}
人就像命运下的蝼蚁,谁也无法操控自己的人生.