SCU2016-02 B题 (缩点+LCA)

来源:互联网 发布:手机淘宝不能买彩票吗 编辑:程序博客网 时间:2024/06/15 23:22

分析:

把强联通分支全部缩成点,变成一颗树,然后跑一下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 200005using 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 ;}
0 0
原创粉丝点击