题解 P4246 【[SHOI2008]堵塞的交通】

scallop

2018-03-14 21:29:54

Solution

这道题真是一道非常**好**的的题目。 我们考虑使用线段树维护连通性。分别维护一个区间中 $$[l_1,r_1],[l_1,l_2],[l_1,r_2],[l_2,r_1],[l_2,r_2],[r_1,r_2]$$ 这些点的连通性。 我们可以通过一定的讨论来得到 $O(1)$ 的方法通过子树更新信息(有些复杂,见代码) 然后我们可以完成单点修改了。 考虑询问操作。我们发现从点 $x_c$ 走到 $y_c$ 可能有四种情况: $$1:x_c\to y_c$$ $$2:x_c\to x_{!c}\to y_c$$ $$3:x_c\to y_{!c}\to y_c$$ $$4:x_c\to x_{!c}\to y_{!c}\to y_c$$ 其中我们令 $!c$ 表示同一列的另一行。那么我们只需要分情况判断是否可以到达就行了。 ```cpp #include <algorithm> #include <iostream> #include <fstream> #include <cstring> #include <cstdlib> #include <complex> #include <string> #include <cstdio> #include <vector> #include <bitset> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <map> #include <set> using namespace std; struct segment { int l; int r; int sum[2]; bool e[3][2]; }; struct return_val { bool e[3][2]; bool operator = (const return_val &x) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 2; ++j) e[i][j] = x.e[i][j]; } } }; const int MAXN = 2e5 + 100; int n, cnt; bool a[MAXN][2]; segment tree[MAXN]; void pushup(int p) { if (tree[p].l == tree[p].r) return; int l = p * 2, r = p * 2 + 1, mid = (tree[p].l + tree[p].r) / 2; memset(tree[p].e, 0, sizeof tree[p].e); tree[p].e[0][0] = (tree[l].e[0][0] && tree[r].e[0][0] && a[mid][0]) || (tree[l].e[0][1] && tree[r].e[1][0] && a[mid][1]); tree[p].e[0][1] = (tree[l].e[0][0] && tree[r].e[0][1] && a[mid][0]) || (tree[l].e[0][1] && tree[r].e[1][1] && a[mid][1]); tree[p].e[1][0] = (tree[l].e[1][0] && tree[r].e[0][0] && a[mid][0]) || (tree[l].e[1][1] && tree[r].e[1][0] && a[mid][1]); tree[p].e[1][1] = (tree[l].e[1][0] && tree[r].e[0][1] && a[mid][0]) || (tree[l].e[1][1] && tree[r].e[1][1] && a[mid][1]); tree[p].e[2][0] = tree[l].e[2][0] || (tree[p].e[0][1] && tree[p].e[1][1]) || (tree[p].e[0][0] && tree[p].e[1][0]) || (tree[p].e[0][0] && tree[p].e[1][1] && tree[r].e[2][1]) || (tree[l].e[0][0] && tree[l].e[1][1] && tree[r].e[2][0] && a[mid][0] && a[mid][1]); tree[p].e[2][1] = tree[r].e[2][1] || (tree[p].e[0][0] && tree[p].e[0][1]) || (tree[p].e[1][0] && tree[p].e[1][1]) || (tree[p].e[0][0] && tree[p].e[1][1] && tree[l].e[2][0]) || (tree[r].e[0][0] && tree[r].e[1][1] && tree[l].e[2][1] && a[mid][0] && a[mid][1]); } void add_row(int p, int x) { if (tree[p].l == tree[p].r && tree[p].l == x) tree[p].e[0][0] = tree[p].e[0][1] = tree[p].e[1][0] = tree[p].e[1][1] = tree[p].e[2][0] = tree[p].e[2][1] = true; else if (tree[p].l <= x && tree[p].r >= x) { int mid = (tree[p].l + tree[p].r) / 2; if (x > mid) add_row(p * 2 + 1, x); else add_row(p * 2, x); pushup(p); } } void sub_row(int p, int x) { if (tree[p].l == tree[p].r && tree[p].l == x) { tree[p].e[0][0] = tree[p].e[1][1] = true; tree[p].e[1][0] = tree[p].e[0][1] = false; tree[p].e[2][0] = tree[p].e[2][1] = false; } else if (tree[p].l <= x && tree[p].r >= x) { int mid = (tree[p].l + tree[p].r) / 2; if (x > mid) sub_row(p * 2 + 1, x); else sub_row(p * 2, x); pushup(p); } } void add_column(int p, int x, int c) { if (tree[p].l == tree[p].r && tree[p].l == x) a[x][c] = true, tree[p].sum[c] = 1; else if (tree[p].l <= x && tree[p].r >= x) { int mid = (tree[p].l + tree[p].r) / 2; if (x > mid) add_column(p * 2 + 1, x, c); else add_column(p * 2, x, c); pushup(p); } } void sub_column(int p, int x, int c) { if (tree[p].l == tree[p].r && tree[p].l == x) a[x][c] = false, tree[p].sum[c] = 0; else if (tree[p].l <= x && tree[p].r >= x) { int mid = (tree[p].l + tree[p].r) / 2; if (x > mid) sub_column(p * 2 + 1, x, c); else sub_column(p * 2, x, c); pushup(p); } } void open(int l1, int r1, int l2, int r2) { if (l1 == l2) add_row(1, l1); else { if (l1 > l2) swap(l1, l2); if (!a[l1][r1]) { add_column(1, l1, r1); } } } void close(int l1, int r1, int l2, int r2) { if (l1 == l2) sub_row(1, l1); else { if (l1 > l2) swap(l1, l2); if (a[l1][r1]) sub_column(1, l1, r1); } } return_val query_direct(int p, int l, int r) { if (tree[p].l == l && tree[p].r == r) return (return_val){{tree[p].e[0][0], tree[p].e[0][1], tree[p].e[1][0], tree[p].e[1][1], tree[p].e[2][0], tree[p].e[2][1]}}; else { return_val t1, t2; int mid = (tree[p].l + tree[p].r) / 2; if (r > mid) t2 = query_direct(p * 2 + 1, max(mid + 1, l), r); if (l <= mid) t1 = query_direct(p * 2, l, min(mid, r)); if (l > mid) return t2; else if (r <= mid) return t1; else { return_val ret; ret.e[0][0] = (t1.e[0][0] && t2.e[0][0] && a[mid][0]) || (t1.e[0][1] && t2.e[1][0] && a[mid][1]); ret.e[0][1] = (t1.e[0][0] && t2.e[0][1] && a[mid][0]) || (t1.e[0][1] && t2.e[1][1] && a[mid][1]); ret.e[1][0] = (t1.e[1][0] && t2.e[0][0] && a[mid][0]) || (t1.e[1][1] && t2.e[1][0] && a[mid][1]); ret.e[1][1] = (t1.e[1][0] && t2.e[0][1] && a[mid][0]) || (t1.e[1][1] && t2.e[1][1] && a[mid][1]); ret.e[2][0] = t1.e[2][0] || (ret.e[0][1] && ret.e[1][1]) || (ret.e[0][0] && ret.e[1][0]) || (ret.e[0][0] && ret.e[1][1] && t2.e[2][1]) || (t1.e[0][0] && t1.e[1][1] && t2.e[2][0] && a[mid][0] && a[mid][1]); ret.e[2][1] = t2.e[2][1] || (ret.e[0][0] && ret.e[0][1]) || (ret.e[1][0] && ret.e[1][1]) || (ret.e[0][0] && ret.e[1][1] && t1.e[2][0]) || (t2.e[0][0] && t2.e[1][1] && t1.e[2][1] && a[mid][0] && a[mid][1]); return ret; } } } int query_left(int l, int r, int c) { while (l < r) { int mid = (l + r) / 2; return_val j = query_direct(1, mid, r); if (j.e[c][c]) r = mid; else l = mid + 1; } return r; } int query_right(int l, int r, int c) { while (l < r) { int mid = (l + r + 1) / 2; return_val j = query_direct(1, l, mid); if (j.e[c][c]) l = mid; else r = mid - 1; } return l; } bool query(int l1, int r1, int l2, int r2) { if (l1 > l2) { swap(l1, l2); swap(r1, r2); } return_val t = query_direct(1, l1, l2); if (t.e[r1][r2]) return true; return_val t1 = query_direct(1, 1, l1), t2 = query_direct(1, l2, n); bool ld = t1.e[2][1], rd = t2.e[2][0]; if (ld && t.e[r1 ^ 1][r2]) return true; if (rd && t.e[r1][r2 ^ 1]) return true; if (ld && rd && t.e[r1 ^ 1][r2 ^ 1]) return true; return false; } void build(int p, int l, int r) { tree[p].l = l; tree[p].r = r; if (tree[p].l != tree[p].r) { int mid = (l + r) / 2; build(p * 2, l, mid); build(p * 2 + 1, mid + 1, r); } else tree[p].e[0][0] = tree[p].e[1][1] = true; } int main() { ios::sync_with_stdio(false); cin >> n; build(1, 1, n); while (true) { string s; cin >> s; if (s[0] == 'E') break; int l1, c1, l2, c2; cin >> c1 >> l1 >> c2 >> l2; --c1; --c2; if (s[0] == 'O') open(l1, c1, l2, c2); if (s[0] == 'C') close(l1, c1, l2, c2); if (s[0] == 'A') { if (query(l1, c1, l2, c2)) printf("Y\n"); else printf("N\n"); } } return 0; } ```