【BZOJ2594】【WC2006】水管局長資料加強版
阿新 • • 發佈:2019-01-29
【題目連結】
【思路要點】
- 若題目僅包含詢問操作,顯然我們只需保留一棵圖的最小生成樹,在樹上詢問兩點間邊權的最大值即可。
- 而本題中多了一種刪邊操作,但沒有強制線上,因此,我們可以將操作離線,轉化為加邊操作。
- 用LinkCutTree維護動態最小生成樹即可。
- 時間複雜度\(O((M+Q)LogN)\)。
【程式碼】
#include<bits/stdc++.h> using namespace std; #define MAXN 300005 #define MAXM 1000005 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } struct LinkCutTree { struct Node { int child[2], father, up; int index, Max, home; bool rev; } a[MAXN]; int size; int hx[MAXN], hy[MAXN]; void pushdown(int root) { if (a[root].rev == false) return; swap(a[root].child[0], a[root].child[1]); if (a[root].child[0]) a[a[root].child[0]].rev ^= true; if (a[root].child[1]) a[a[root].child[1]].rev ^= true; a[root].rev = false; } bool get(int x) { return x == a[a[x].father].child[1]; } void update(int root) { a[root].Max = a[root].index; a[root].home = root; if (a[root].child[0]) { int tmp = a[root].child[0]; if (a[tmp].Max > a[root].Max) { a[root].Max = a[tmp].Max; a[root].home = a[tmp].home; } } if (a[root].child[1]) { int tmp = a[root].child[1]; if (a[tmp].Max > a[root].Max) { a[root].Max = a[tmp].Max; a[root].home = a[tmp].home; } } } void rotate(int x) { if (a[x].father == 0) return; pushdown(a[x].father); pushdown(x); int f = a[x].father, g = a[f].father; bool tmp = get(x), tnp = get(f); a[x].up = a[f].up; a[f].up = 0; a[f].child[tmp] = a[x].child[tmp ^ 1]; a[a[x].child[tmp ^ 1]].father = f; a[f].father = x; a[x].child[tmp ^ 1] = f; a[x].father = g; a[g].child[tnp] = x; update(f); update(x); } void splay(int x) { pushdown(x); for (int f = a[x].father; (f = a[x].father); rotate(x)) if ((f = a[x].father)) { if (get(f) == get(x)) rotate(f); else rotate(x); } } void access(int x) { splay(x); int tmp = a[x].child[1]; a[x].child[1] = 0; update(x); a[tmp].father = 0; a[tmp].up = x; while (a[x].up) { int f = a[x].up; splay(f); tmp = a[f].child[1]; a[f].child[1] = x; update(f); a[tmp].father = 0; a[tmp].up = f; a[x].father = f; a[x].up = 0; splay(x); } } void reverse(int x) { access(x); splay(x); a[x].rev ^= true; } void init(int n) { size = n; } void link(int x, int y) { access(x); splay(x); reverse(y); access(y); a[x].child[1] = y; a[y].father = x; update(x); } void link(int x, int y, int z) { size++; hx[size] = x; hy[size] = y; a[size].Max = a[size].index = z; a[size].home = size; link(x, size); link(y, size); } int query(int x, int y) { reverse(x); access(y); splay(y); return a[y].Max; } void cut(int x, int y) { reverse(x); access(y); splay(x); a[x].child[1] = 0; a[y].father = 0; update(x); } void cut(int x) { cut(x, hx[x]); cut(x, hy[x]); } void addedge(int x, int y, int z) { reverse(x); access(y); splay(y); if (a[y].Max <= z) return; cut(a[y].home); link(x, y, z); } } LCT; struct edge {int x, y, len; }; int n, m, q; int f[MAXN], k[MAXN]; int x[MAXN], y[MAXN], z[MAXN]; bool disable[MAXM]; edge a[MAXM]; map <int, int> home[MAXN]; vector <int> ans; int F(int x) { if (f[x] == x) return x; else return f[x] = F(f[x]); } bool cmp(edge a, edge b) { return a.len < b.len; } int main() { read(n), read(m), read(q); for (int i = 1; i <= m; i++) read(a[i].x), read(a[i].y), read(a[i].len); sort(a + 1, a + m + 1, cmp); for (int i = 1; i <= m; i++) { if (a[i].x > a[i].y) swap(a[i].x, a[i].y); home[a[i].x][a[i].y] = i; } for (int i = 1; i <= q; i++) { read(k[i]), read(x[i]), read(y[i]); if (k[i] == 2) { if (x[i] > y[i]) swap(x[i], y[i]); int tmp = home[x[i]][y[i]]; disable[tmp] = true; z[i] = a[tmp].len; } } LCT.init(n); for (int i = 1; i <= n; i++) f[i] = i; for (int i = 1; i <= m; i++) { if (disable[i]) continue; int rx = F(a[i].x), ry = F(a[i].y); if (rx == ry) continue; f[rx] = ry; LCT.link(a[i].x, a[i].y, a[i].len); } for (int i = q; i >= 1; i--) { if (k[i] == 1) ans.push_back(LCT.query(x[i], y[i])); else LCT.addedge(x[i], y[i], z[i]); } reverse(ans.begin(), ans.end()); for (unsigned i = 0; i < ans.size(); i++) printf("%d\n", ans[i]); return 0; }