对时间进行线段树分治,可撤销并查集维护连通性。
把每条边出现的时间看作是几条线段,区间修改。
于是做完了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 15;
int n, m, q;
pair<int, int> edge[N];
int p[N], sz[N];
int find(int x) { return (p[x] == x) ? x : find(p[x]); }
vector<int> range[N];
struct Tree {
int l, r;
vector<int> edge;
} tr[N << 2];
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void change(int u, int l, int r, int k) {
if (l > r) return;
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].edge.push_back(k);
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) change(u << 1, l, r, k);
if (r > mid) change(u << 1 | 1, l, r, k);
}
int stk[N], top = 0;
void solve(int u) {
int pre = top;
for (int i : tr[u].edge) {
int x = edge[i].first, y = edge[i].second;
x = find(x), y = find(y);
if (x == y) continue;
if (sz[x] < sz[y]) p[x] = y, sz[y] += sz[x], stk[++top] = x;
else p[y] = x, sz[x] += sz[y], stk[++top] = y;
}
if (tr[u].l == tr[u].r) puts( (sz[find(1)] == n) ? "Connected" : "Disconnected");
if (tr[u].l != tr[u].r) solve(u << 1), solve(u << 1 | 1);
while (top > pre) {
int x = stk[top], y = p[x]; top--;
sz[y] -= sz[x], p[x] = x;
}
if (tr[u].l == tr[u].r) return;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) p[i] = i, sz[i] = 1;
for (int i = 1; i <= m; i++) range[i].push_back(0);
for (int i = 1; i <= m; i++) scanf("%d%d", &edge[i].first, &edge[i].second);
scanf("%d", &q);
for (int i = 1, c, x; i <= q; i++) {
scanf("%d", &c);
while (c--) {
scanf("%d", &x);
range[x].push_back(i);
}
}
build(1, 1, q);
for (int i = 1; i <= m; i++) range[i].push_back(q + 1);
// for (int i = 1; i <= m; i++, puts(""))
// for (int j : range[i]) cout << j << ' ';
for (int i = 1; i <= m; i++) {
for (int j = 0; j < range[i].size() - 1; j++) {
int l = range[i][j] + 1, r = range[i][j + 1] - 1;
change(1, l, r, i);
// if (l <= r) cout << '\t' << i << ' ' << l << ' ' << r << endl;
}
}
solve(1);
return 0;
}