AHOI2013 连通图 题解
题意简述
给定一个有 \(n\) 个点和 \(m\) 条边的图,有 \(k\) 次询问,问当删除一些边后,图是否还联通
思路
首先看到本题,可以想到用并查集维护图的联通性,然而,并查集是不支持随机删除的,因此我们可以将删去边改为将没删除的边连接上,到下一个询问时撤销当前的加边操作。
但是如果全部删去,则得到复杂度 \(O(mk)\) ,非常明显这会超时,这里运用线段树分治(不会线段树分治的小朋友戳这里),将操作加到线段树上后,离线算出答案并输出。
代码实现
#include <iostream>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
#define PII pair<int, int>
const int N = 1e5+10;
const int M = 2e5+10;
typedef struct{
int u, v;
}Edge;
Edge edge[M];
class DSU{
private:
int n;
int dep[N];
int fa[N];
int cnt[N];
stack<PII>sta;
public:
inline int size(){
return sta.size();
}
inline void init(int __n){
n = __n;
for(int i = 1; i <= n; i++){
fa[i] = i;
dep[i] = 0;
cnt[i] = 1;
}
while(!sta.empty())
sta.empty();
}
inline int find(int x){
if(x == fa[x])
return x;
return find(fa[x]);
}
inline bool check(int x, int y){
return find(x) == find(y);
}
inline bool check(){
return cnt[find(1)] == n;
}
inline void join(int x, int y){
x = find(x);
y = find(y);
if(x == y)
return;
if(dep[x] > dep[y])
swap(x, y);
if(dep[x] == dep[y])
dep[y]++;
fa[x] = y;
cnt[y] += cnt[x];
sta.push(make_pair(x, y));
}
inline void undo(int ct){
while(size() != ct){
auto [x, y] = sta.top();
sta.pop();
if(dep[x]+1 == dep[y])
dep[y]--;
fa[x] = x;
cnt[y] -= cnt[x];
}
}
};
DSU UN;
vector<Edge>tree[N<<2];
inline int lchild(int x){return x<<1;}
inline int rchild(int x){return x<<1|1;}
inline void add(int p, int pl, int pr, int l, int r, Edge x){
if(pl >= l && pr <= r){
tree[p].push_back(x);
return;
}
int mid = (pl+pr) >> 1;
if(mid >= l)
add(lchild(p), pl, mid, l, r, x);
if(mid < r)
add(rchild(p), mid+1, pr, l, r, x);
return;
}
inline void dfs(int p, int pl, int pr){
int tmp = UN.size();
for(auto [x, y] : tree[p])
UN.join(x, y);
if(pl == pr){
if(UN.check())
puts("Connected");
else
puts("Disconnected");
}
else{
int mid = (pl+pr) >> 1;
dfs(lchild(p), pl, mid);
dfs(rchild(p), mid+1, pr);
}
UN.undo(tmp);
}
int bef[M];
int main(){
int n, m;
cin >> n >> m;
UN.init(n);
for(int i = 1; i <= m; i++)
cin >> edge[i].u >> edge[i].v;
int k;
cin >> k;
for(int i = 1; i <= k; i++){
int c;
cin >> c;
while(c--){
int x;
cin >> x;
if(bef[x]+1 <= i-1)
add(1, 1, k, bef[x]+1, i-1, edge[x]);
bef[x] = i;
}
}
for(int i = 1; i <= m; i++)
add(1, 1, k, bef[i]+1, k, edge[i]);
dfs(1, 1, k);
return 0;
}

浙公网安备 33010602011771号