P2898 [USACO08JAN]haybale猜测Haybale Guessing
好题.
搬运一下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;
}