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

*/

posted @ 2025-05-12 16:35  Hootime  阅读(2)  评论(0)    收藏  举报