F - Well-defined Path Queries on a Namori
题意:
给一个 n n n个点 n n n条边的无向图,有 Q Q Q个询问,询问两个点的简单路径是否唯一。
题解:
首先,这个图是可以看成一棵树加了一条边,即图中有且仅有一个环。
可以通过并查集找到环中的一个点,根据这个点进行dfs可以找出环。
其次,若两点之间的路径上存在环,则不存在唯一的简单路径。
因此,我们可以对环上的点的子树进行染色,若在同一个子树上,则路径唯一。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 10;
int n, par[maxn], f, col[maxn], q;
vector<int>G[maxn], cri;
int find(int x) { return (x == par[x] ? x : par[x] = find(par[x])); }
void merge(int a, int b) {
int x = find(a), y = find(b);
if (x == y)return;
par[x] = y;
}
bool dfs1(int p,int u) {
if (p != 0 && u == f) {
return 1;
}
for (auto v : G[u]) {
if (p == v)continue;
if (dfs1(u, v)) {
cri.push_back(u);
return 1;
}
}
return 0;
}
void dfs2(int p, int u, int c) {
col[u] = c;
for (auto v : G[u]) {
if (v == p)continue;
dfs2(u, v, c);
}
}
int main() {
cin >> n;
f = 0;
for (int i = 0; i <= n; i++)par[i] = i;
for (int i = 1; i <= n; i++) {
int u, v; cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
if (!f && find(u) == find(v)) {
f = u;
}
merge(u, v);
}
dfs1(0, f);
int t = 0;
for (auto x : cri) {
col[x] = ++t;
}
for (auto u : cri) {
for (auto v : G[u]) {
if (col[v])continue;
dfs2(u, v, col[u]);
}
}
cin >> q;
while (q--) {
int u, v; cin >> u >> v;
if (col[u] == col[v])cout << "Yes\n";
else cout << "No\n";
}
return 0;
}