#2466. 「POI2014」卡片 Card
阿新 • • 發佈:2020-11-21
將每個位置拆成兩個狀態 \(0/1\),分別表示該牌選擇正面/反面,如果 \(v_{i,a} \le v_{i + 1, b}\) 則在這兩個狀態間連邊,
最終就是看兩頭是否存在一條通路。
可以用線段樹來維護每段區間兩頭的四種情況是否可能連通即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) #define fi first #define se second const int N = 2e5 + 10, inf = 0x3f3f3f3f, mod = 1e9 + 7; typedef pair <int, int> P; typedef long long LL; int n, m, a[N][2]; bool c[N<<2][2][2], t[N<<2]; inline void chk_(int o, int l, int r) { int mid = (l + r)>>1; c[o][0][0] = c[o][0][1] = c[o][1][0] = c[o][1][1] = t[o] = 0; if (!t[o<<1] || !t[o<<1|1]) return; rep (i, 0, 1) rep (j, 0, 1) rep (x, 0, 1) rep (y, 0, 1) if (a[mid][x] <= a[mid + 1][y]) c[o][i][j] = max(c[o][i][j], c[o<<1][i][x] && c[o<<1|1][y][j]); t[o] = c[o][0][0] || c[o][0][1] || c[o][1][0] || c[o][1][1]; } void build_(int o, int l, int r) { if (l == r) { c[o][0][0] = c[o][1][1] = t[o] = 1; return; } int mid = (l + r)>>1; build_(o<<1, l, mid), build_(o<<1|1, mid + 1, r); chk_(o, l, r); } void update_(int o, int l, int r, int x) { if (l == r) return; int mid = (l + r)>>1; if (x <= mid) update_(o<<1, l, mid, x); else update_(o<<1|1, mid + 1, r, x); chk_(o, l, r); } int main() { scanf("%d", &n); rep (i, 1, n) scanf("%d%d", &a[i][0], &a[i][1]); build_(1, 1, n); scanf("%d", &m); while (m--) { int u, v; scanf("%d%d", &u, &v); swap(a[u], a[v]); update_(1, 1, n, u), update_(1, 1, n, v); printf("%s\n", t[1] ? "TAK" : "NIE"); } }