P5227 [AHOI2013]連通圖 題解
阿新 • • 發佈:2022-04-17
一道線段樹分治套路好題。
將刪邊變為加邊,考慮一條邊能夠加到哪些集合裡面。注意,這裡不能直接新增,也就是說對於邊 \((x,y)\),如果其在集合 \(t\) 裡面,不能直接插入到區間 \([1,t-1],[t+1,m]\) 中,這也是我的一個思維定式導致的誤區。
正確的做法是應該都存下來,然後分段處理,設邊 \((x,y)\) 所在集合構成的序列為 \(\{p_q\}\),那麼我們應當將 \((x,y)\) 插入 \([1,p_1-1],[p1+1,p_2-1],...,[p_q+1,k]\) 裡面,這塊用一個 vector / set 或者別的資料結構維護。
然後直接大力線段樹分治即可,注意空間問題,因為到最後插入的邊數是和集合的總元素個數相關的,所以不要開太小。
GitHub:CodeBase-of-Plozia
Code:
/* ========= Plozia ========= Author:Plozia Problem:P5227 [AHOI2013]連通圖 Date:2022/3/30 ========= Plozia ========= */ #include <bits/stdc++.h> using std::vector; typedef long long LL; const int MAXN = 1e5 + 5; int n, m, fa[MAXN], Height[MAXN], sum, Top, cntEdge, ans[MAXN]; vector <int> v[MAXN << 1]; struct node { int x, y; } a[MAXN << 1]; struct EDGE { int x, y, l, r; } Edge[MAXN << 3]; struct STA { int x, y, f; } sta[MAXN << 3]; struct SgT { vector <int> E; }tree[MAXN << 2]; int Read() { int sum = 0, fh = 1; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1; for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + (ch ^ 48); return sum * fh; } int Max(int fir, int sec) { return (fir > sec) ? fir : sec; } int Min(int fir, int sec) { return (fir < sec) ? fir : sec; } void Insert(int p, int l, int r, int k, int lp, int rp) { if (lp >= l && rp <= r) { tree[p].E.push_back(k); return ; } int mid = (lp + rp) >> 1; if (l <= mid) Insert(p << 1, l, r, k, lp, mid); if (r > mid) Insert(p << 1 | 1, l, r, k, mid + 1, rp); } int gf(int x) { while (x != fa[x]) x = fa[x]; return x; } void Merge(int x, int y) { if (Height[x] > Height[y]) std::swap(x, y); sta[++Top] = (STA){x, y, Height[x] == Height[y] }; fa[x] = y; Height[y] += sta[Top].f; } void dfs(int p, int l, int r) { int las = Top; for (int i = 0; i < tree[p].E.size(); ++i) { int x = gf(Edge[tree[p].E[i]].x), y = gf(Edge[tree[p].E[i]].y); if (x == y) continue; Merge(x, y); --sum; } if (l == r) ans[l] = sum; else { int mid = (l + r) >> 1; dfs(p << 1, l, mid); dfs(p << 1 | 1, mid + 1, r); } while (Top > las) { STA tmp = sta[Top]; --Top; fa[tmp.x] = tmp.x; Height[tmp.y] -= tmp.f; ++sum; } } int main() { n = Read(), m = Read(); sum = n; for (int i = 1; i <= n; ++i) fa[i] = i, Height[i] = 1; for (int i = 1; i <= m; ++i) a[i].x = Read(), a[i].y = Read(); int k = Read(); for (int i = 1; i <= k; ++i) { int c = Read(); while (c--) { int tmp = Read(); v[tmp].push_back(i); } } for (int i = 1; i <= m; ++i) { v[i].push_back(0); v[i].push_back(k + 1); std::sort(v[i].begin(), v[i].end()); for (int j = 1; j < v[i].size(); ++j) { if (v[i][j - 1] + 1 <= v[i][j] - 1) { Edge[++cntEdge] = (EDGE){a[i].x, a[i].y, v[i][j - 1] + 1, v[i][j] - 1}; Insert(1, v[i][j - 1] + 1, v[i][j] - 1, cntEdge, 1, k); } } } dfs(1, 1, k); for (int i = 1; i <= k; ++i) puts((ans[i] == 1) ? "Connected" : "Disconnected"); return 0; }