Solution - P5058 [ZJOI2004] 嗅探器
好题。
思路
首先一眼瞪出 Tarjan。然后显然题目要找 \(u \to v\) 路径上的割点。
一个神奇的思路是从 \(u\) 开始 Tarjan,判割点的时候判一下 \(v\) 是否在该割点的子树上。就很神奇。
代码
#include <bits/stdc++.h>
#define rbool register bool
#define rint register int
#define rllong register long long
#define llong long long
#define N 200005
#define M 1000006
using namespace std;
int to[M], nxt[M], head[N], gsiz = 1;
#define mkarc(u,v) (++gsiz,to[gsiz]=v,nxt[gsiz]=head[u],head[u]=gsiz)
int dfn[N], low[N], dfcnt;
int cut[N], cnt[N], vis1[M], vis2[N];
int n, s, t;
int ans = 1e9+7;
inline void tarjan(rint u){
dfn[u] = low[u] = ++dfcnt;
for(rint i = head[u]; i; i = nxt[i]){
if(vis1[i^1]) continue;
vis1[i] = true;
rint v = to[i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u] && u != s && u != t && dfn[t] >= dfn[v])
ans = min(ans, u);
}
else low[u] = min(low[u], dfn[v]);
}
return;
}
int main(){
scanf("%d", &n);
while(true){
rint u, v;
scanf("%d %d", &u, &v);
if(!u && !v) break;
mkarc(u, v), mkarc(v, u);
}
scanf("%d %d", &s, &t);
tarjan(s);
if(ans >= 1e9) puts("No solution");
else printf("%d", ans);
return 0;
}
/*
5
1 2
1 3
2 4
3 4
4 5
0 0
1 5
*/