目录
- 1.题目
- 2.思路
- 3.代码
默认大家都会并查集了
1.题目
小美认为,在人际交往中,但是随着时间的流逝,朋友的关系也是会慢慢变淡的,最终朋友关系就淡忘了。
现在初始有一些朋友关系,存在一些事件会导致两个人淡忘了他们的朋友关系。小美想知道某一时刻中,某两人是否可以通过朋友介绍互相认识?
事件共有 2 种:
1 u v:代表编号 u 的人和编号 v 的人淡忘了他们的朋友关系。
2 u v:代表小美查询编号 u 的人和编号 v 的人是否能通过朋友介绍互相认识。
注:介绍可以有多层,比如 2 号把 1 号介绍给 3 号,然后 3 号再把 1 号介绍给 4 号,这样 1 号和 4 号就认识了。
输入描述
第一行输入三个正整数n,m,q,代表总人数,初始的朋友关系数量,发生的事件数量。接下来的m行,每行输入两个正整数u,v,代表初始编号u的人和编号v的人是朋友关系。接下来的q行,每行输入三个正整数op,u,v,含义如题目描述所述。
2.思路
显然,查找公共祖先的很容易就能想到并查集的数据结构
但并查集因为将子节点到祖先节点的边压缩了,所以我们并不好维护边的删除,所以采用反向建立并查集
3.代码
#include<bits/stdc++.h>
using namespace std;const int N = 100007;
int p[N], n, m, q;int find(int x){if(p[x] != x) p[x] = find(p[x]);return p[x];
}void merge(int x, int y){int px = find(x), py = find(y);if(px != py) p[px] = py;
}
int main(){set<pair<int, int>> edges, del_edges;cin >> n >> m >> q;for(int i = 1; i <= n; i++) p[i] = i;for(int i = 1; i <= m; i++){int u, v;cin >> u >> v;edges.insert({u, v});}vector<vector<int>> queries(q);for (int i = 0; i < q; i++) {int op, u, v;cin >> op >> u >> v;queries[i] = {op, u, v};if (op == 1) {del_edges.insert({u, v});}}for (auto &[u, v] : edges) {if (del_edges.find({u, v}) == del_edges.end() && del_edges.find({v, u}) == del_edges.end()) {merge(u, v);}}vector<string> ans;for (int i = q - 1; i >= 0; i--) {int op = queries[i][0];int u = queries[i][1];int v = queries[i][2];if (op == 2) {if (find(u) == find(v)) ans.push_back("Yes");else ans.push_back("No");} else {merge(u, v);}}reverse(ans.begin(), ans.end());for(auto s : ans){cout << s << endl;}return 0;
}