Loj 121. 「离线可过」动态图连通性

题目描述

Solution

加边和删边看成每个边在某一段时间内存在,线段树分治即可

并查集按秩合并即可支持撤销

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
#define maxn 5010
#define maxm 500010
using namespace std;

int n, m;

struct Edge {
int fr, to;

friend bool operator < (const Edge &u, const Edge &v) {
if (u.fr == v.fr) return u.to < v.to;
return u.fr < v.fr;
}
} ask[maxm]; map<Edge, int> mp;

int fa[maxn], dep[maxn], st[maxn], top;
void init_fa(int n) { for (int i = 1; i <= n; ++i) fa[i] = i, dep[i] = 1; }

int find(int x) {
while (x != fa[x]) x = fa[x];
return x;
}

void merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return ;
if (dep[fx] > dep[fy]) swap(fx, fy);
fa[fx] = fy; st[++top] = fx;
if (dep[fx] == dep[fy]) ++dep[fy], st[top] *= -1;
}

void undo(int _top) {
while (top > _top) {
int x = st[top--];
if (x < 0) x = -x, --dep[fa[x]];
fa[x] = x;
}
}

#define lc i << 1
#define rc i << 1 | 1
vector<Edge> T[maxm * 4];
void update(int i, int l, int r, int L, int R, const Edge &v) {
if (l > R || r < L) return ;
if (L <= l && r <= R) return T[i].push_back(v);
int m = l + r >> 1;
update(lc, l, m, L, R, v); update(rc, m + 1, r, L, R, v);
}

void query(int i, int l, int r) {
if (d[r] - d[l - 1] == 0) return;
int m = l + r >> 1, _top = top;
for (auto v : T[i]) merge(v.fr, v.to);
if (l == r) {
int u = ask[l].fr, v = ask[l].to;
if (u) cout << (find(u) == find(v) ? "Y" : "N") << "\n";
undo(_top); return ;
}
query(lc, l, m); query(rc, m + 1, r);
undo(_top);
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> m; init_fa(n);
for (int i = 1; i <= m; ++i) {
int opt, x, y; cin >> opt >> x >> y;
if (x > y) swap(x, y);
if (opt == 2) ask[i] = { x, y };
else if (opt == 0) mp[{ x, y }] = i;
else update(1, 1, m, mp[{ x, y }], i - 1, { x, y }), mp.erase({ x, y });
}
for (auto u : mp) update(1, 1, m, u.second, m, u.first);
query(1, 1, m);
return 0;
}