【省內訓練2018-11-23】Graph
阿新 • • 發佈:2018-11-27
【思路要點】
- 離線詢問,為每一條邊找到一個刪除時間。
- 將過程倒過來,按照刪除時間倒序加入每一條邊。
- 我們將加入的邊分為兩類,加入後連線兩個不同的聯通塊的稱為樹邊,剩餘的邊稱為非樹邊。
- 顯然,樹邊的加入不會產生新的雙連通分量,因此,我們可以預先將所有的樹邊加入圖中,並處理出形成的森林中每個節點的深度等資訊。
- 之後,我們每加入一條非樹邊,就會將森林中一條樹鏈上所有的節點合併起來,可以通過並查集實現。
- 用 配合啟發式合併維護顏色集合,時間複雜度 。
- 也可以用線段樹合併維護顏色集合,時間複雜度 。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; const int MAXM = 5e5 + 5; typedef long long ll; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 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; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } map <int, int> col[MAXN]; vector <int> a[MAXN], adj[MAXN], qry[MAXM]; ll ans[MAXM], curr; int n, m, k, q, num[MAXN], father[MAXN], depth[MAXN], f[MAXN]; int x[MAXM], y[MAXM], t[MAXM], p[MAXM], timer; int F(int x) { if (f[x] == x) return x; else return f[x] = F(f[x]); } void dfs(int pos, int fa) { f[pos] = pos; father[pos] = fa; depth[pos] = depth[fa] + 1; col[pos][num[pos]] = 1; for (auto x : a[pos]) if (x != fa) dfs(x, pos); } ll func(int x) { return x * (x - 1ll) / 2; } void merge(int x, int y) { x = F(x), y = F(y); int tx = x, ty = y; while (tx != ty) { if (depth[tx] > depth[ty]) tx = F(father[tx]); else ty = F(father[ty]); } int lca = tx; while (x != lca) { if (col[x].size() > col[lca].size()) swap(col[x], col[lca]); for (auto val : col[x]) { curr -= func(val.second); curr -= func(col[lca][val.first]); col[lca][val.first] += val.second; curr += func(col[lca][val.first]); } f[x] = F(father[x]); x = F(x); } x = y; while (x != lca) { if (col[x].size() > col[lca].size()) swap(col[x], col[lca]); for (auto val : col[x]) { curr -= func(val.second); curr -= func(col[lca][val.first]); col[lca][val.first] += val.second; curr += func(col[lca][val.first]); } f[x] = F(father[x]); x = F(x); } } int main() { read(n), read(m), read(k), read(q); for (int i = 1; i <= n; i++) read(num[i]); for (int i = 1; i <= m; i++) { read(x[i]), read(y[i]); adj[x[i]].push_back(i); adj[y[i]].push_back(i); } static bool flg[MAXM]; qry[1].push_back(0); for (int i = 1; i <= q; i++) { int x; read(x); if (!flg[x]) { flg[x] = true; for (auto y : adj[x]) if (t[y] == 0) t[y] = ++timer; } qry[timer + 1].push_back(i); } for (int i = 1; i <= m; i++) if (t[i] == 0) t[i] = ++timer; for (int i = 1; i <= m; i++) p[t[i]] = i; for (int i = 1; i <= n; i++) f[i] = i; memset(flg, false, sizeof(flg)); for (int i = m; i >= 1; i--) { int now = p[i]; if (F(x[now]) != F(y[now])) { flg[now] = true; a[x[now]].push_back(y[now]); a[y[now]].push_back(x[now]); f[F(x[now])] = F(y[now]); } } for (int i = 1; i <= n; i++) if (depth[i] == 0) dfs(i, 0); for (int i = m; i >= 1; i--) { int now = p[i]; if (!flg[now]) merge(x[now], y[now]); for (auto x : qry[i]) ans[x] = curr; } for (int i = 0; i <= q; i++) writeln(ans[i]); return 0; }