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;
}
posted @ 2024-06-06 23:29  HurryCine  阅读(4)  评论(0)    收藏  举报