传送门

非常裸的一题

就是边双连通缩点成一棵树,然后树上所有边都是桥

那么连接任意两点,树的路径上都不再是桥

所以就找树的直径即可

但是这里会出现重边,那么需要特殊的处理方式

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 2e6+10;
const int N  = 2e5+10;
int n,m;
vector<int>vec[N];
struct edge{
	int u,to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt].u=u,d[cnt].to=v,d[cnt].nxt = head[u],head[u] = cnt;
}
int id,dfn[N],low[N],bridge[maxn],bcc[N],bccn,qiao;
int vis[N],stac[N],top; 
void tarjan(int u,int fa)
{
	bool flag=0;
	dfn[u]=low[u]=++id;	stac[++top]=u, vis[u] = 1;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( !dfn[v] )
		{
			tarjan(v,u); 
			low[u]=min( low[u],low[v] );
			if( low[v]>dfn[u] )
				qiao++,bridge[i]=bridge[i^1] = 1;
		}
		else if( vis[v] )//不通过父子回边,或者这条边有重边 
		{
			if( v!=fa||flag )
				low[u]=min( low[u],dfn[v] );
			else	flag=1;
		}
	}
	if( low[u]==dfn[u] )
	{
		int temp; bccn++;
		while( temp=stac[top--] )
		{
			vis[temp] = 0;
			bcc[temp]=bccn;//属于哪个双连通
			if( temp==u )	break; 
		}
	}
}
int f[N],g[N],ans;
void dfs(int u,int fa)
{
	vis[u] = 1;
	for(int i=0;i<vec[u].size();i++)
	{
		int v = vec[u][i];
		if( vis[v] )	continue;
		dfs( v,u );
		if( f[v]+1>=f[u] )
			g[u] = f[u], f[u] = f[v]+1;
		else if( f[v]+1>g[u] )	g[u] = f[v]+1;
	}
	ans = max( ans,f[u]+g[u] );
}
int main()
{
	while( cin >> n >> m && (n+m) )
	{
		for(int i=1;i<=m;i++)
		{
			int l,r; scanf("%d%d",&l,&r);
			add(l,r); add(r,l);
		}
		tarjan(1,1);
		for(int i=2;i<=cnt;i++)
		{
			int u = d[i].u, v = d[i].to;
			if( bcc[u]!=bcc[v] )
				vec[bcc[u]].push_back(bcc[v]);
		}
		dfs(1,0);
		cout << qiao-ans << endl;
		for(int i=1;i<=n;i++)
			vec[i].clear(), f[i] = g[i] = vis[i] = head[i] = dfn[i] = low[i] = 0;
		for(int i=1;i<=cnt;i++)	bridge[i] = 0;
		cnt = 1; ans = bccn = id = qiao = top = 0;
	}
}