#Tarjan,树的直径#CF1000E We Need More Bosses

题目

给定一个\(n\)个点\(m\)条边的无向图,找到两个点\(s,t\),使得\(s\)\(t\)必须经过的边最多


分析

桥就是必须经过的边,考虑给无向图缩点,
按照桥建一棵树,那么就转换成了求树的直径


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=600011; struct node{int y,next;}e[N<<1],E[N<<1];
int dfn[N],low[N],hs[N],as[N],Et=1,et=1,tot,ext,n,m,bridge[N<<1],col[N],ans,dp[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
inline void tarjan(int x,int F){
	dfn[x]=low[x]=++tot;
	for (rr int i=hs[x];i;i=E[i].next)
	if (!dfn[E[i].y]){
	    tarjan(E[i].y,i^1);
	    low[x]=min(low[x],low[E[i].y]);
	    if (dfn[x]<low[E[i].y])
		    bridge[i]=bridge[i^1]=1;
	}else if (i!=F) low[x]=min(low[x],dfn[E[i].y]);
}
inline void add(int x,int y){
	e[++et]=(node){y,as[x]},as[x]=et;
	e[++et]=(node){x,as[y]},as[y]=et;
}
inline void dfs(int x){
	col[x]=ext;
	for (rr int i=hs[x];i;i=E[i].next)
	if (!bridge[i]&&!col[E[i].y]) dfs(E[i].y);
	    else if (bridge[i]&&col[E[i].y])
		    add(ext,col[E[i].y]);    
}
inline void Dfs(int x,int fa){
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa){
		Dfs(e[i].y,x);
		ans=max(ans,dp[e[i].y]+dp[x]+1);
		dp[x]=max(dp[x],dp[e[i].y]+1);
	}
} 
signed main(){
	ext=n=iut(),m=iut();
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut();
		E[++Et]=(node){y,hs[x]},hs[x]=Et;
		E[++Et]=(node){x,hs[y]},hs[y]=Et;
	}
	for (rr int i=1;i<=n;++i)
	    if (!dfn[i]) tarjan(i,0);
	for (rr int i=1;i<=n;++i)
	    if (!col[i]) ++ext,dfs(i);
	Dfs(ext,0);
	return !printf("%d",ans);
}
posted @ 2021-07-07 11:26  lemondinosaur  阅读(29)  评论(0编辑  收藏  举报