【洛谷 P1712】 [NOI2016]区间 (线段树+尺取)

题目链接
emmm看起来好像无从下手,
\(l_i,r_i\)这么大,肯定是要离散化的。
然后我们是选\(m\)个区间,我们先对这些区间按长度排个序也不影响。
排序后,设我们取的\(m\)个区间的编号\(b_1,b_2,...,b_m\)
\(b_m\)确定,我们肯定是要尽量使\(b_1,b_2,...,b_{m-1}\)尽量接近\(b_m\)的,这样可使代价最小。
所以,就可以尺取了。
定义两个指针\(l,r\),首先\(r\)指针不停右移覆盖一遍扫到的区间直到满足条件有一个点被连续覆盖\(m\)次,怎么判断?显然维护一棵最大值线段树就好了。
当满足条件,就让\(l\)指针右移直到不满足条件,更新答案。

#include 
#include 
using std::sort;
#define INF 2147483647
const int MAXN = 650010;
int n, m, q;
char ch;
inline int max(int a, int b){
    return a > b ? a : b;
}
inline int min(int a, int b){
    return a > b ? b : a;
}
inline int read(){
    q = 0; ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9') { q = q * 10 + ch - '0'; ch = getchar(); }
    return q;
}
struct Seg{
    int l, r, len;
    bool operator < (const Seg A) const{
        return len < A.len;
    }
}s[MAXN];
struct LSH{
    int id, pos, val;
    bool operator < (const LSH A) const{
        return val < A.val;
    }
}p[MAXN << 1];
int cnt, num;
namespace SegTree{
    #define left (now << 1)
    #define right (now << 1 | 1)
    int Max[MAXN << 2 << 1], lazy[MAXN << 2 << 1];
    inline void pushup(int now){
        Max[now] = max(Max[left], Max[right]);
    }
    inline void pushdown(int now){
        if(lazy[now]){
            Max[left] += lazy[now];
            Max[right] += lazy[now];
            lazy[left] += lazy[now];
            lazy[right] += lazy[now];
            lazy[now] = 0;
        }
    }
    void update(int now, int l, int r, int wl, int wr, int p){
        if(l >= wl && r <= wr){ Max[now] += p; lazy[now] += p; return; }
        pushdown(now);
        int mid = (l + r) >> 1;
        if(wl <= mid) update(left, l, mid, wl, min(mid, wr), p);
        if(wr > mid) update(right, mid + 1, r, max(mid + 1, wl), wr, p);
        pushup(now);
    }
    int query(int now, int l, int r, int wl, int wr){
        if(l >= wl && r <= wr) return Max[now];
        int ans = 0;
        pushdown(now);
        int mid = (l + r) >> 1;
        if(wl <= mid) ans = max(ans, query(left, l, mid, wl, min(mid, wr)));
        if(wr > mid) ans = max(ans, query(right, mid + 1, r, max(mid + 1, wl), wr));
        return ans;
    }
}using namespace SegTree;
int ans = INF;
int main(){
    n = read(); m = read();
    for(int i = 1; i <= n; ++i){
        s[i].l = read(); s[i].r = read();
        s[i].len = s[i].r - s[i].l;
        p[++cnt].val = s[i].l; p[cnt].id = i; p[cnt].pos = 1;
        p[++cnt].val = s[i].r; p[cnt].id = i; p[cnt].pos = 2;
    } p[0].val = -1;
    sort(p + 1, p + cnt + 1);
    for(int i = 1; i <= cnt; ++i)
        if(p[i].pos == 1)
            if(p[i].val != p[i - 1].val)
                s[p[i].id].l = ++num;
            else s[p[i].id].l = num;
        else
            if(p[i].val != p[i - 1].val)
                s[p[i].id].r = ++num;
            else s[p[i].id].r = num;
    sort(s + 1, s + n + 1);
    int l = 1, r = 0;
    while(r < n){
        while(r < n && Max[1] < m){
            ++r;
            update(1, 1, num, s[r].l, s[r].r, 1);
        }
        if(Max[1] < m) break;
        int tmp;
        while(Max[1] >= m) tmp = s[l].len, update(1, 1, num, s[l].l, s[l].r, -1), ++l;
        ans = min(ans, s[r].len - tmp);
    }
    printf("%d\n", ans == INF ? -1 : ans);
    return 0;
}

转载于:https://www.cnblogs.com/Qihoo360/p/9739303.html

你可能感兴趣的:(【洛谷 P1712】 [NOI2016]区间 (线段树+尺取))