Luogu P2898 [USACO08JAN]Haybale Guessing G

题目描述

https://www.luogu.com.cn/problem/P2898

Solution

首先我们考虑什么情况下会出现矛盾

  1. 同一权值的区间的交为空
  2. 一个低权值的区间被一些高权值的区间的并完全包含

首先我们考虑二分 我也不知道为什么能想到二分

我们思考二分的作用是什么,假如我们认为前x次操作出现矛盾

也就意味着我们可以改变问答的顺序,类似于一种离线的思想

我们考虑将区间按照权值从大到小排序

用并查集维护区间的并,一次判断两种情况即可

这道题的一个坑是区间不能离散化

原因是对于一个区间如果内部没有其他区间的端点到话,在离散化之后就只剩下端点

换句话说就是有可能本来没有被覆盖,离散化之后被覆盖了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 1000010
#define maxm 25010
#define cn const node
using namespace std;

int n, m;

struct node {
int l, r, w, id;

friend bool operator < (cn &u, cn &v) { return u.w > v.w; }
} a[maxm];

int fa[maxn];
void init_fa() { for (int i = 1; i <= n + 1; ++i) fa[i] = i; }

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

inline void merge(int l, int r) { while (l < r) l = fa[l] = find(l + 1); }


bool check(int x) {
init_fa();
for (int i = 1; i <= m; ++i) {
if (a[i].id > x) continue;
int L = a[i].l, R = a[i].r, l = a[i].l, r = a[i].r, w = a[i].w;
while (a[i + 1].w == w) { ++i;
if (a[i].id > x) continue;
L = max(L, a[i].l); l = min(l, a[i].l);
R = min(R, a[i].r); r = max(r, a[i].r);
}
if (L > R || find(L) >= R + 1) return 1;
merge(find(l), r + 1);
}
return 0;
}

int main() {
freopen("1.in", "r", stdin);
cin >> n >> m;
for (int i = 1; i <= m; ++i) scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].w), a[i].id = i;
sort(a + 1, a + m + 1);
int l = 1, r = m, mid, ans = 0;
while (l <= r) {
mid = l + r >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans << endl;
return 0;
}