P2898 [USACO08JAN]haybale猜测Haybale Guessing

好题.
搬运一下luogu的题解, 讲的挺清楚的.

题意:给出一些区间的最小值 求问 最早哪个问题会产生矛盾 输出
我们可以二分判断 哪个地方最早出现矛盾
然后每次针对二分的一个值 我去判断一下是否成立 我首先针对权值排序
然后从大到小去覆盖 出现第一个无法覆盖的区域我就返回false

当然, 此处无法覆盖的区域其实有两种情况 :

  1. 多个区间最小值相同却没有一个共同包含的区间;
  2. 多个区间最小值相同且有一个共同包含的区间, 但是这个区间被一个最小值更大的区间包含.

为了处理这两种不合法的情况, 我们先二分不合法端点所在位置, 然后按照所给的最小值从大到小排序.
对于情况一, 我们记录下相同权值的区间中左端点的最大值右端点的最小值. 假如左端点的最大值 \(>\) 右端点的最小值, 就说明这之间没有被这些区间完全覆盖, 显然不合法.
情况二用线段树或者并查集都可以.
假如遇见了这两种情况, 就缩小二分的右端点即可.
这里我用的线段树.

#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 10;
const int MAXQ = 25000 + 10;
inline int read(){
    char ch = getchar(); int x = 0;
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x;
}

int N, Q;
struct Query
{
    int l, r, v;
    bool operator >(const Query &rhs) const {
        return v > rhs.v;
    }
}que[MAXQ], q[MAXQ];

namespace stree
{
    #define mid ((l + r) >> 1)
    #define ls (o << 1)
    #define rs ((o << 1) | 1)

    struct Node
    {
        int val, tag;
    }node[MAXN << 2];

    inline void pushup(int o) {
        node[o].val = node[ls].val + node[rs].val;
    }

    inline void givetag(int o, int l, int r, int v) {
        node[o].val = (r - l + 1) * v;
        node[o].tag = v;
    }

    inline void pushdown(int o, int l, int r) {
        int &v = node[o].tag;
        if(v == 0) return;
        givetag(ls, l, mid, v), givetag(rs, mid + 1, r, v);
        v = 0;
    } 

    void modify(int o, int l, int r, int a, int b, int v) {
        if(l > b || r < a) return ;
        if(a <= l && r <= b) return givetag(o, l, r, v);
        pushdown(o, l, r);
        modify(ls, l, mid, a, b, v), modify(rs, mid + 1, r, a, b, v); 
        return pushup(o);
    }

    int query(int o, int l, int r, int a, int b) {
        if(l > b || r < a) return 0;
        if(a <= l && r <= b) return node[o].val;
        pushdown(o, l, r);
        return query(ls, l, mid, a, b) + query(rs, mid + 1, r, a, b);
    }
    #undef mid
    #undef ls
    #undef rs
}

inline bool check(int x) {
    using namespace stree;
    memcpy(q, que, (x + 1) * sizeof(Query));
    sort(q + 1, q + x + 1, greater<Query>());
    memset(node, 0, ((N + 1) << 2) * sizeof(Node));
    for(int i = 1; i <= x; i++) {
        int lmin = q[i].l, rmin = q[i].r, lmax = q[i].l, rmax = q[i].r;
        while(i + 1 <= x && q[i].v == q[i + 1].v) {
            ++i;
            lmin = min(lmin, q[i].l), rmin = min(rmin, q[i].r);
            lmax = max(lmax, q[i].l), rmax = max(rmax, q[i].r);
        }
        if(lmax > rmin || query(1, 1, N, lmax, rmin) == (rmin - lmax + 1)) return false;
        modify(1, 1, N, lmin, rmax, 1);
    }
    return true;
}

int main(){
    // freopen("p2898.in", "r", stdin);
    cin>>N>>Q;
    for(int i = 1; i <= Q; i++)
        que[i].l = read(), que[i].r = read(), que[i].v = read();
    int l = 1, r = Q + 1;
    while(l < r) {
        int mid = (l + r) >> 1;
        if(check(mid)) l = mid + 1;
        else r = mid;
    }
    if(r == Q + 1) puts("0");
    else printf("%d\n", l);
    return 0;
}
posted @ 2018-10-18 17:45  俺是小程  阅读(173)  评论(0编辑  收藏  举报