当 A→B→C 有一条简单路径时,需要满足 C→B 中 A 不是必须经过的点,且 A→B 中 C 不是必须经过的点。
因此考虑将图转化为圆方树后树链剖分,枚举 A→B 的树上路径中是否有 C。再枚举 C→B 上是否有 A。如果都没有就输出 Yes,否则输出 No。
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define MAXN 200001
int n, m, q, u, v, cnt, ssum, res, a, b, c, lca;
int id[MAXN<<1];
int dfn[MAXN], low[MAXN];
int dep[MAXN<<1], fa[MAXN<<1], top[MAXN<<1], siz[MAXN<<1], son[MAXN<<1];
vector<int> e[MAXN], t[MAXN<<1];
stack<int> st;
void tarjan(int x){
dfn[x] = low[x] = ++cnt;
st.push(x);
for (auto i: e[x]){
if (!dfn[i]){
tarjan(i);
low[x] = min(low[x], low[i]);
if (low[i] == dfn[x]){
++ssum;
t[ssum].push_back(x);
t[x].push_back(ssum);
while (st.top() != i){
t[st.top()].push_back(ssum);
t[ssum].push_back(st.top());
st.pop();
}
t[ssum].push_back(i);
t[i].push_back(ssum);
st.pop();
}
}else low[x] = min(low[x], dfn[i]);
}
}
void dfs1(int x, int f){
fa[x] = f;
dep[x] = dep[f] + 1;
siz[x] = 1;
for (auto i: t[x]){
if (i != f){
dfs1(i, x);
siz[x] += siz[i];
if (siz[son[x]] < siz[i]) son[x] = i;
}
}
}
void dfs2(int x, int tp){
top[x] = tp;
if (!son[x]) return;
dfs2(son[x], tp);
for (auto i: t[x]){
if (i != fa[x] && i != son[x]) dfs2(i, i);
}
}
int LCA(int x, int y){
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if (dep[x] < dep[y]) return x;
return y;
}
void f(int a, int b, int c){
lca = LCA(b, c);
while (c != lca){
if (c == a){
cout << "No";
exit(0);
}
c = fa[c];
}
if (c == a){
cout << "No";
exit(0);
}
while (b != lca){
if (b == a){
cout << "No";
exit(0);
}
b = fa[b];
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> a >> b >> c;
while (m--){
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
ssum = n;
tarjan(1);
dfs1(1, 0);
dfs2(1, 1);
f(a, b, c);
f(c, b, a);
cout << "Yes";
return 0;
}