Luogu P3569 [POI2014]KAR-Cards

题目描述

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

Solution

如果没有修改的话显然就是个贪心

然后我们注意到对于一段区间只有两种答案,选 $a$ 右端点的最小值和选 $b$ 右端点的最小值

然后我们发现这东西可以拿线段树维护,然后就没了

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
#include <iostream>
#include <cstdio>
#define maxn 200010
#define cS const Seg
#define INF 1000000000
using namespace std;

int n, m, a[maxn], b[maxn];

#define lc i << 1
#define rc i << 1 | 1
struct Seg {
int l1, r1, l2, r2;

Seg() {}
Seg(int _l1, int _r1, int _l2, int _r2) { l1 = _l1; r1 = _r1; l2 = _l2; r2 = _r2; }
} T[maxn * 4];
inline Seg maintain(cS &ls, cS &rs) {
Seg o; o = Seg(INF, INF, INF, INF);
if (ls.r1 <= rs.l1) o.l1 = ls.l1, o.r1 = rs.r1;
if (ls.r1 <= rs.l2) o.l1 = ls.l1, o.r1 = min(o.r1, rs.r2);
if (ls.r2 <= rs.l1) o.l2 = ls.l2, o.r2 = rs.r1;
if (ls.r2 <= rs.l2) o.l2 = ls.l2, o.r2 = min(o.r2, rs.r2);
return o;
}

void build(int i, int l, int r) {
if (l == r) return (void) (T[i] = Seg(a[l], a[l], b[l], b[l]));
int m = l + r >> 1;
build(lc, l, m); build(rc, m + 1, r);
T[i] = maintain(T[lc], T[rc]);
}

void update(int i, int l, int r, int k, int v1, int v2) {
if (l == r) return (void) (T[i] = Seg(v1, v1, v2, v2));
int m = l + r >> 1;
if (k <= m) update(lc, l, m, k, v1, v2);
else update(rc, m + 1, r, k, v1, v2);
T[i] = maintain(T[lc], T[rc]);
}

int main() {
cin >> n;
for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &b[i]);
build(1, 1, n); cin >> m;
for (int i = 1; i <= m; ++i) {
int x, y; scanf("%d%d", &x, &y);
swap(a[x], a[y]); swap(b[x], b[y]);
update(1, 1, n, x, a[x], b[x]); update(1, 1, n, y, a[y], b[y]);
puts(min(T[1].r1, T[1].r2) < INF ? "TAK" : "NIE");
}
return 0;
}