【BZOJ1018】[SHOI2008]堵塞的交通
阿新 • • 發佈:2018-12-25
【BZOJ1018】[SHOI2008]堵塞的交通
題面
題解
菊隊講要用線段樹維護連通性,但是好像沒人寫
解法一
將所有的加邊刪邊離線,然後以最近刪除時間為邊權,$LCT$維護最大生成樹即可
程式碼
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <map> using namespace std; inline int gi() { register int data = 0, w = 1; register char ch = 0; while (!isdigit(ch) && ch != '-') ch = getchar(); if (ch == '-') w = -1, ch = getchar(); while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); return w * data; } const int MAX_N = 100005; const int INF = 1e9; struct Node { int fa, ch[2], v, d; bool rev; } t[MAX_N << 2]; int stk[MAX_N << 2], top; void pushup(int x) { t[x].d = x; if (t[t[x].d].v > t[t[t[x].ch[0]].d].v) t[x].d = t[t[x].ch[0]].d; if (t[t[x].d].v > t[t[t[x].ch[1]].d].v) t[x].d = t[t[x].ch[1]].d; } void pushrev(int x) { t[x].rev ^= 1; swap(t[x].ch[0], t[x].ch[1]); } void pushdown(int x) { if (!t[x].rev) return ; if (t[x].ch[0]) pushrev(t[x].ch[0]); if (t[x].ch[1]) pushrev(t[x].ch[1]); t[x].rev = 0; } int get(int x) { return t[t[x].fa].ch[1] == x; } bool isroot(int x) { return (t[t[x].fa].ch[1] != x) && (t[t[x].fa].ch[0] != x); } void rotate(int x) { int k = get(x), y = t[x].fa, z = t[y].fa; if (!isroot(y)) t[z].ch[get(y)] = x; t[x].fa = z; t[t[x].ch[k ^ 1]].fa = y, t[y].ch[k] = t[x].ch[k ^ 1]; t[x].ch[k ^ 1] = y, t[y].fa = x; pushup(y), pushup(x); } void splay(int x) { stk[top = 1] = x; for (int i = x; !isroot(i); i = t[i].fa) stk[++top] = t[i].fa; for (int i = top; i; i--) pushdown(stk[i]); while (!isroot(x)) { int y = t[x].fa; if (!isroot(y)) (get(x) ^ get(y)) ? rotate(x) : rotate(y); rotate(x); } } void access(int x) { for (int y = 0; x; y = x, x = t[x].fa) splay(x), t[x].ch[1] = y, pushup(x); } int findroot(int x) { access(x); splay(x); while (t[x].ch[0]) pushdown(x), x = t[x].ch[0]; return x; } void makeroot(int x) { access(x); splay(x); pushrev(x); } void split(int x, int y) { makeroot(x); access(y); splay(y); } void link(int x, int y) { makeroot(x); t[x].fa = y; } void cut(int x, int y) { split(x, y); t[y].ch[0] = t[x].fa = 0, pushup(y); } int N, C, tot; struct Opt { int t, op, x1, x2, del; } a[MAX_N << 1]; map<pair<int, int>, int> mp; int main () { C = gi(); for ( ; ; ) { char ch[10]; scanf("%s", ch); if (ch[0] == 'E') break; int op, r1 = gi() - 1, c1 = gi(), r2 = gi() - 1, c2 = gi(), x1 = r1 * C + c1, x2 = r2 * C + c2; if (x1 > x2) swap(x1, x2); if (ch[0] == 'O') op = 0; if (ch[0] == 'C') op = 1; if (ch[0] == 'A') op = 2; ++N; if (op == 0) mp[pair<int, int>(x1, x2)] = N, a[N].del = INF; if (op == 1) a[mp[pair<int, int>(x1, x2)]].del = N; a[N].t = N, a[N].op = op, a[N].x1 = x1, a[N].x2 = x2; } tot = 2 * C; for (int i = 0; i <= tot; i++) t[i].v = INF; for (int i = 1; i <= N; i++) { int x1 = a[i].x1, x2 = a[i].x2, del = a[i].del; if (a[i].op == 0) { if (findroot(x1) == findroot(x2)) { split(x1, x2); int d = t[x2].d; if (t[d].v >= del) continue; else cut(x1, d), cut(x2, d); t[++tot].v = del; link(x1, tot), link(x2, tot); } else t[++tot].v = del, link(x1, tot), link(x2, tot); } if (a[i].op == 1) if (findroot(x1) == findroot(x2)) { split(x1, x2); int d = t[x2].d; if (t[d].v > a[i].t) continue; cut(x1, d), cut(x2, d); } if (a[i].op == 2) { if (findroot(x1) == findroot(x2)) puts("Y"); else puts("N"); } } return 0; }
解法二
線段樹分治板子題,然而我並不會