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;
}

posted @ 2017-04-04 07:04  Sky_miner  阅读(210)  评论(1编辑  收藏  举报