無向圖 G(V,E),初始無邊。支援三種操作(Q ≤ 20000,N ≤ 1000):
I u v:插入邊 (u,v)(保證不存在)D u v:刪除邊 (u,v)(保證存在)Q u v:查詢 u,v 是否連通每次查詢運行 BFS。插入/刪除 O(1),查詢 O(N+E)。最壞 O(Q·N) 可能超時,但 N=1000、稀疏圖下常能通過。
維護所有當前邊的集合。查詢用併查集 O(α(N))。插入:加入邊並 union。刪除:標記邊失效,重建整個併查集(遍歷所有有效邊)。重建 O(E),刪除操作較多時較慢。
結合兩者優點:
vector adj[MAXN];
int father[MAXN];
int n;
int find(int x) { return father[x]==x ? x : father[x]=find(father[x]); }
void unite(int a, int b) { father[find(a)] = find(b); }
void rebuild() {
for (int i=1;i<=n;++i) father[i]=i;
for (int u=1; u<=n; ++u)
for (int v : adj[u])
if (u < v) unite(u, v); // 無向邊只處理一次
}
bool query(int u, int v) { return find(u)==find(v); }
void insertEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
unite(u, v); // 直接合併
}
void deleteEdge(int u, int v) {
// 從鄰接表移除(線性查找,deg ≤ 1000)
auto erase = [&](vector& vec, int val) {
for (auto it=vec.begin(); it!=vec.end(); ++it)
if (*it==val) { vec.erase(it); break; }
};
erase(adj[u], v);
erase(adj[v], u);
rebuild(); // 簡單暴力重建,N=1000 時極快
}
| 操作 | 解法一 | 解法二 | 解法三 |
|---|---|---|---|
| Insert | O(1) | O(α(N)) | O(α(N)) + O(deg) |
| Delete | O(deg) | O(E) 重建 | O(deg) + O(N+E) 重建 |
| Query | O(N+E) | O(α(N)) | O(α(N)) |
實測解法三在 POJ 2838 上 546ms AC,兼顧簡潔與效率。