NOI2016 区间

UOJ

尺取法吼题哇

先将 \(l,r\) 离散化,然后按照区间长度排序成单调不下降的,然后跟着尺取法的套路来搞,线段树维护就行了。

顺便提一句,开始我没有发现线段树要维护的区间范围可能是 \([1,2N]\) 只开了 \(4\) 倍的空间,结果 \(RE\) 到死。实际上要开 \(8\) 倍,我真菜

#include <iostream>
#include <cstdio>
#include <algorithm>

const int max_n = 500000 + 5;
const int inf = 0x7f7f7f7f;

struct Ask
{
    int l, r, len;
}P[max_n];

int N, M, Ans = inf, Tot;
int A[max_n << 1], maxv[max_n << 3], lazy[max_n << 3];

inline int read()
{
    register int x = 0;
    register char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch))
    {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return x;
}

void update(int o, int l, int r, int ql, int qr, int v)
{
    if(ql <= l && r <= qr)
    {
        maxv[o] += v;
        lazy[o] += v;
        return;
    }
    if(lazy[o])
    {
        lazy[o << 1] += lazy[o];
        lazy[o << 1 | 1] += lazy[o];
        maxv[o << 1] += lazy[o];
        maxv[o << 1 | 1] += lazy[o];
        lazy[o] = 0;
    }
    int mid = l + r >> 1;
    if(ql <= mid) update(o << 1, l, mid, ql, qr, v);
    if(mid < qr) update(o << 1 | 1, mid + 1, r, ql, qr, v);
    maxv[o] = std::max(maxv[o << 1], maxv[o << 1 | 1]);
}

bool cmp(Ask x, Ask y)
{
    return (x.len < y.len);
}

int main()
{
    N = read();
    M = read();
    for(int i = 1; i <= N; ++i)
    {
        A[i] = P[i].l = read();
        A[i + N] = P[i].r = read();
        P[i].len = P[i].r - P[i].l;
    }
    std::sort(&A[1], &A[N << 1 | 1]);
    std::sort(&P[1], &P[N + 1], cmp);
    Tot = std::unique(&A[1], &A[N << 1 | 1]) - &A[1];
    for(int i = 1; i <= N; ++i)
    {
        P[i].l = std::lower_bound(&A[1], &A[Tot + 1], P[i].l) - &A[0], P[i].r = std::lower_bound(&A[1], &A[Tot + 1], P[i].r) - &A[0];
    }
    for(int l = 1, r = 0; ; )
    {
        while(r < N && maxv[1] < M)
        {
            ++r;
            update(1, 1, Tot, P[r].l, P[r].r, 1);
        }
        if(maxv[1] < M) break;
        Ans = std::min(Ans, P[r].len - P[l].len);
        update(1, 1, Tot, P[l].l, P[l].r, -1);
        ++l;
    }
    printf("%d\n", (Ans == inf) ? -1 : Ans);
    return 0;
}

转载于:https://www.cnblogs.com/zcdhj/p/8457899.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值