P5227 [AHOI2013] 连通图 题解

考虑线段树分治。

每一条边存在的时间是若干个区间,在线段树上将这些区间加入这条边,离线之后使用可撤销并查集按秩合并。如果 11 点的根所在集合大小为 nn,则是连通,输出 rl+1r-l+1Connected\texttt{Connected},否则递归往下即可。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
using namespace std;

const int N = 2e5 + 5;

int n, m, k;
vector<int> V[N];
int u[N], v[N];

class Union_Find
{
public:
	int fa[N], sz[N];
	void Init()
	{
		for (int i = 0; i < N; i++) fa[i] = i, sz[i] = 1;
	}
	int find(int u)
	{
		return(fa[u] == u ? u : find(fa[u]));
	}
	pair<int, int> merge(int u, int v)
	{
		if ((u = find(u)) == (v = find(v)))
		{
			exit(-1);
		}
		if (sz[u] < sz[v]) swap(u, v);
		fa[v] = u;
		sz[u] += sz[v];
		return make_pair(u, v);
	}
	void del(int u, int v)
	{
		fa[v] = v;
		sz[u] -= sz[v];
	}
}uf;

class SegmentTree
{
public:
	struct Node
	{
		int l, r;
		vector<pair<int, int>> v;
	}tr[N << 2];
	void build(int u, int l, int r)
	{
		tr[u] = { l, r };
		tr[u].v.clear();
		tr[u].v.shrink_to_fit();
		if (l == r) return;
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
	}
	void update(int u, int l, int r, auto v)
	{
		if (tr[u].l >= l and tr[u].r <= r)
		{
			tr[u].v.emplace_back(v);
			return;
		}
		int mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid) update(u << 1, l, r, v);
		if (r > mid) update(u << 1 | 1, l, r, v);
	}
	void solve(int u)
	{
		stack<pair<int, int>> st;
		for (auto& j : tr[u].v)
		{
			if (uf.find(j.first) == uf.find(j.second)) continue;
			st.push(uf.merge(j.first, j.second));
		}
		if (uf.sz[uf.find(1)] == n)
		{
			for (int i = tr[u].l; i <= tr[u].r; i++)
			{
				cout << "Connected\n";
			}
		}
		else
		{
			if (tr[u].l == tr[u].r) cout << "Disconnected\n";
			else
			{
				solve(u << 1);
				solve(u << 1 | 1);
			}
		}
		while (st.size())
		{
			uf.del(st.top().first, st.top().second);
			st.pop();
		}
	}
}sgt;

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
	{
		cin >> u[i] >> v[i];
	}
	cin >> k;
	sgt.build(1, 1, k);
	uf.Init();
	for (int i = 1; i <= k; i++)
	{
		int c;
		cin >> c;
		for (int j = 1; j <= c; j++)
		{
			int x;
			cin >> x;
			V[x].emplace_back(i);
		}
	}
	for (int i = 1; i <= m; i++)
	{
		if (V[i].empty())
		{
			sgt.update(1, 1, k, make_pair(u[i], v[i]));
		}
		else
		{
			if (V[i].front() != 1)
			{
				sgt.update(1, 1, V[i].front() - 1, make_pair(u[i], v[i]));
			}
			for (int j = 1; j < V[i].size(); j++)
			{
				int l = V[i][j - 1] + 1, r = V[i][j] - 1;
				if (l <= r) sgt.update(1, l, r, make_pair(u[i], v[i]));
			}
			if (V[i].back() != k) sgt.update(1, V[i].back() + 1, k, make_pair(u[i], v[i]));
		}
	}
	sgt.solve(1);
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示