P5227 [AHOI2013] 连通图 题解
考虑线段树分治。
每一条边存在的时间是若干个区间,在线段树上将这些区间加入这条边,离线之后使用可撤销并查集按秩合并。如果
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!