P5058 [ZJOI2004] 嗅探器 题解
显然,答案的点一定是割点,找割点我们可以用Tarjan算法,但是割点不一定是答案点。我们不妨从\(dfn\)序的角度出发,如果是答案点的话,假设\(u\)是割点,\(u-v\)是一条割边,一定是有\(dfn[v] \le dfn[b]\)的。这表明\(b\)是遍历\(v\)的子树的时候遍历到的。如果\(dfn[v] > dfn[b]\),则有两种情况,第一种情况是在遍历\(v\)之前就已经访问过了\(b\),那么\(v\)这个点一定无法阻断所有的走向\(b\)的通路。第二种情况是\(dfn[b]=0\),那么这个时候压根没访问到\(b\),\(v\)这个点自然也不是答案。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int dfn[N],low[N],idx;
int n,a,b;
vector<int> e[N];
bool flag[N];
void Tarjan(int u,int fa){
dfn[u]=low[u]=++idx;
for(int v:e[u]){
if(!dfn[v]){
Tarjan(v,u);
low[u]=min(low[u],low[v]);
if(u!=fa&&low[v]>=dfn[u]&&!flag[u]&&dfn[v]<=dfn[b]){
flag[u]=true;
}
}else if(v^fa){
low[u]=min(low[u],dfn[v]);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
while(1){
int u,v;
cin>>u>>v;
if(u==0&&v==0) break;
else{
e[u].push_back(v),e[v].push_back(u);
}
}
cin>>a>>b;
Tarjan(a,a);
for(int i=1;i<=n;i++){
if(flag[i]){
cout<<i;
return 0;
}
}
cout<<"No solution";
return 0;
}
总结:处理割点有关问题的时候,可以从\(dfn\)序的角度出发进行考虑。

浙公网安备 33010602011771号