【ZJOI2004】嗅探器

某军搞信息对抗实战演习,红军成功地侵入了蓝军的内部网络
蓝军共有两个信息中心,红军计划在某台中间服务器上安装一个嗅探器
从而能够侦听到两个信息中心互相交换的所有信息
但是蓝军的网络相当的庞大,数据包从一个信息中心传到另一个信息中心可以不止有一条通路
现在需要你尽快地解决这个问题
应该把嗅探器安装在哪个中间服务器上才能保证所有的数据包都能被捕获

tarjan求割点的灵活变式

考虑一下我们求割点的方法:
寻找以v为根的搜索子树是否能延伸到时间戳小于u的节点来判断u是否为割点

如果满足了以上条件,那么这个节点u就是割点

而如果我们以一个信息中心a为根开始搜索,找到一个非根的割点u
若此时对应的子树根v的时间戳小于b的时间戳,则说明b存在于v为根的这颗子树内

证明:
由于dfn随dfs序更新,若还没搜到b,则其dfn为0,或dfn不为0而小于v
则说明b在进入v以前已经被搜到了
另外,b等于u的情况是不合题意的

所以把求割点的方式改一下就好了

代码:

#include<bits/stdc++.h>
#define N 500010
using namespace std;

int n,u,v,s,t;

struct Edge
{
	int next,to;
}edge[N<<1];
int cnt=0,head[N];

inline void add_edge(int from,int to)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	head[from]=cnt;
}

int low[N],dfn[N],tms=0;
bool cut[N];
void tarjan(int u)
{
	low[u]=dfn[u]=++tms;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
			if(u==s) continue;
			else if(dfn[u]<=low[v]&&dfn[v]<=dfn[t]) cut[u]=1;
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

int main()
{
	read(n);
	while(true)
	{
		read(u);read(v);
		if(!u&&!v) break;
		add_edge(u,v);
		add_edge(v,u);
	}
	read(s);read(t);
	tarjan(s);
	for(register int i=1;i<=n;++i)
		if(cut[i]) {printf("%d",i);return 0;}
	puts("No solution");
	return 0;
}
原文地址:https://www.cnblogs.com/tqr06/p/11640948.html