1. 程式人生 > >P2898 [USACO08JAN]haybale猜測Haybale Guessing

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