bzoj4653: [Noi2016]区间

题面在这里

题意:

给出一堆区间,要你选出m个区间使得至少一个点都被覆盖,并且此时花费的代价是最长的区间长减去最短的区间长。
问最小的代价。

做法:

我们考虑一中区间的入场顺序,按照长度从小到大。
我们选出的区间肯定是连续的一段,于是我们用两个指针维护开头和结尾。
进来一段区间,就在线段树上把这一段加一,然后假如某一时刻,有一个点到达了m,就说明这连续一段的区间是可行的就可以更新答案,并且头指针++,看能不能继续更新。
于是扫一遍就好了。

易错点:

线段树下标不要搞错,是离散化以后的数的总数(原来写成n了样例挂了好几发)。

代码:

/*************************************************************
    Problem: bzoj 4653 [Noi2016]区间
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 7324 ms
    Memory: 48172 kb
    Submit_Time: 2018-01-05 10:53:31
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#define mid (l+r>>1)
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long LL;

inline LL read()
{
    char ch = getchar(); LL x = 0; int op = 1;
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') op = -1;
    for (; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
    return op*x;
}

const int N = 1000010;
int n, m, tot;
int mx[N<<2], tag[N<<2], num[N];
struct Node{
    int l, r, len;
}a[N];

const bool cmp(const Node &x, const Node &y) { return x.len < y.len; }
inline void add(int o, int l, int r, int x, int y, int v)
{
    if(l == x && r == y) { tag[o] += v; mx[o] += v; return; }
    if(y <= mid) add(lc, l, mid, x, y, v);
    else if(x > mid) add(rc, mid+1, r, x, y, v);
    else add(lc, l, mid, x, mid, v), add(rc, mid+1, r, mid+1, y, v);
    mx[o] = max(mx[lc], mx[rc]) + tag[o];
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i ++) {
        a[i].l = read(), a[i].r = read();
        num[++ tot] = a[i].l; num[++ tot] = a[i].r;
        a[i].len = a[i].r-a[i].l+1;
    }
    sort(a+1, a+1+n, cmp);
    sort(num+1, num+1+tot); tot = unique(num+1, num+1+tot) - num-1;
    for(int i = 1; i <= n; i ++) {
        a[i].l = lower_bound(num+1, num+1+tot, a[i].l) - num;
        a[i].r = lower_bound(num+1, num+1+tot, a[i].r) - num;
    }
    int h = 1, t = 0; int ans = 1e9;
    while(h <= n) {
        while(t < n && mx[1] < m) {
            t ++;
            add(1, 1, tot, a[t].l, a[t].r, 1);
        }
        if(t == n && mx[1] < m) break;
        ans = min(ans, a[t].len - a[h].len);
        add(1, 1, tot, a[h].l, a[h].r, -1); h ++;
    }
    if(ans == 1e9) puts("-1"); else printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值