分析:
把强联通分支全部缩成点,变成一颗树,然后跑一下LCA,每一次加边都会在树上形成一个环,环上所有的边都将不再是桥,并且把环缩成点。
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define pr(x) cout << #x << ": " << x << " "
#define pl(x) cout << #x << ": " << x << endl;
#define N 100005
#define M 200005
using namespace std ;
struct node
{
int e , next ;
}p[2*M+1000] ;
int head[N] , dfn[N] , low[N] , vist[N] , pre[N] ;
bool mark[N] ;
int n , m , num , cnt , id , q ;
void add( int x , int y )
{
p[num].e = y ;
p[num].next = head[x] ;
head[x] = num++ ;
p[num].e = x ;
p[num].next = head[y] ;
head[y] = num++ ;
}
void dfs( int x )
{
vist[x] = 1 ;
dfn[x] = low[x] = ++id ;
for ( int i = head[x] ; i != -1 ; i = p[i].next )
{
int v = p[i].e ;
if( !vist[v] )
{
pre[v] = x ;
dfs( v ) ;
low[x] = min( low[x] , low[v] ) ;
if ( low[v] > dfn[x] )//map[x][v]就是桥
{
cnt++ ;
mark[v] = true ;
}
}
else if ( vist[v] && v != pre[x] )
low[x] = min( low[x] , dfn[v] ) ;
}
//vist[x] = 2 ;
}
void find( int x , int y )
{
while( dfn[x] > dfn[y] )
{
if ( mark[x] )
{
cnt-- ;
mark[x] = false ;
}
x = pre[x] ;
}
while ( dfn[y] > dfn[x] )
{
if ( mark[y] )
{
cnt-- ;
mark[y] = false ;
}
y = pre[y] ;
}
while ( x!= y )
{
if ( mark[x] )
{
cnt-- ;
mark[x] = false ;
}
if ( mark[y] )
{
cnt-- ;
mark[y] = false ;
}
x = pre[x] ;
y = pre[y] ;
}
}
int main()
{
int i , x , y ;
int cas = 1 ;
while ( scanf ( "%d%d" , &n , &m ) , n + m )
{
memset( head , -1 , sizeof( head )) ;
num = 0 ;
for ( i = 1 ; i <= m ; i++ )
{
scanf ( "%d%d" , &x , &y ) ;
add( x , y ) ;
}
memset( dfn , 0 , sizeof ( dfn )) ;
memset( low , 0 , sizeof ( low )) ;
memset( vist , 0 , sizeof ( vist )) ;
memset( mark , false , sizeof ( mark )) ;
//求强连通,缩点
cnt = id = 0 ;
for ( i = 1 ; i <= n ; i++ )
if ( !dfn[i] )
dfs( i );
scanf ( "%d" , &q );
printf ( "Case %d:\n" , cas++ ) ;
while ( q-- )
{
scanf ( "%d%d" , &x , &y ) ;
//两点是否在同一分支中
if ( low[x] == low[y] )
{
printf ( "%d\n" , cnt ) ;
continue ;
}
//求公共最近祖先
find ( x , y );
printf ( "%d\n" , cnt ) ;
}
printf ( "\n" ) ;
}
return 0 ;
}