P2898 [USACO08JAN]haybale猜測Haybale Guessing
阿新 • • 發佈:2018-11-11
好題.
搬運一下luogu的題解, 講的挺清楚的.
題意:給出一些區間的最小值 求問 最早哪個問題會產生矛盾 輸出
我們可以二分判斷 哪個地方最早出現矛盾
然後每次針對二分的一個值 我去判斷一下是否成立 我首先針對權值排序
然後從大到小去覆蓋 出現第一個無法覆蓋的區域我就返回false
當然, 此處無法覆蓋的區域
其實有兩種情況 :
- 多個區間最小值相同卻沒有一個共同包含的區間;
- 多個區間最小值相同且有一個共同包含的區間, 但是這個區間被一個最小值更大的區間包含.
為了處理這兩種不合法的情況, 我們先二分不合法端點所在位置, 然後按照所給的最小值從大到小排序.
假如遇見了這兩種情況, 就縮小二分的右端點即可.
處理區間這一塊可以用線段樹或者並查集, 這裡我用的線段樹.
#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; }