追捕盗贼

来源:互联网 发布:docker nginx jetty 编辑:程序博客网 时间:2024/04/27 16:42

【COCI2007】追捕盗贼 (Standard IO)
Time Limits: 3000 ms Memory Limits: 65536 KB Detailed Limits

Description

  为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统。警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N。
  警察经常想在罪犯从一个城市逃亡另一个城市的过程中抓住他。侦查员在仔细研究地图,以决定在哪个城市设置障碍,或者断掉某条路。你的计算机系统必须回答以下两种问题:
  1、 如果连接城市G1和G2的路被封掉,罪犯能否从城市A逃到城市B?
  2、 如果城市C被封掉,罪犯能否从城市A逃到城市B?
  编程实现上述计算机系统。

Input

  输入第一行包含两个整数N和E(2<=N<=100000,1<=E<=500000),表示城市和边的数量。
  接下来E行,每行包含两个不同的整数Ai和Bi,表示城市Ai和Bi之间有一条边直接相连,任意两个城市之间最多只有一条边相连。
  接下来一行包含一个整数Q(1<=Q<=300000),表示询问次数。
  接下来Q行,每行包含4个或5个整数,第一个数为1或2,表示询问问题的种类。
  如果问题种类是1,后面跟着4个整数A,B,G1,G2,如上描述表示询问如果G1和G2之间的路封掉罪犯能否从城市A逃到城市B,保证A和B不同,G1和G2之间一定存在路。
  如果问题种类是2,后面跟着三个整数A,B,C,三个数互不相同,表示询问如果封掉城市C,罪犯能否从城市A逃到城市B。
  输入数据保证一开始任意两个城市都可以相互到达。

Output

  每个询问输出一行“yes”或“no”。

Sample Input

13 15

1 2

2 3

3 5

2 4

4 6

2 6

1 4

1 7

7 8

7 9

7 10

8 11

8 12

9 12

12 13

5

1 5 13 1 2

1 6 2 1 4

1 13 6 7 8

2 13 6 7

2 13 6 8

Sample Output

yes

yes

yes

no

yes

这题训练tarjan很到位,既要找割点,也要找割边。对于割点要注意根的情况(如果不特判,根一定被认为是割点)。
思路是把块缩起来,构建新图,在新图上判断是否是子树的情况。对于u,v,若u是割的子树,v不是,则分开。我用了LCA判。不过似乎用dfs序判更好。傻了傻了。

#include<cstdio>#include<cstring>#include<algorithm>#include<map>#include<vector>using namespace std ;#define N 100010#define M 500010#define psb( x ) push_back( x ) #define iter vector< Br_info >::iteratorint n  , Q , i , k , j , g[N] , T , m ;struct edge {    int y , l ;}f[M*2] , Gr[M*2] , Er[M*2] ;map< int , int > G ;void ins( int a , int b ) {    f[++T].y = b , f[T].l = g[a] , g[a] = T ;}int dfn[N] , low[N] , time , de[N] , fa[N] , sta[N] , top , Gt ;int Ntid[N] , Etid[N] ;struct Gstack {    int bridge , obj ;}Gsta[N] ;struct Br_info {    int a , b ;};vector< Br_info > Bri_info[N] ;int h[N] ;void Gins( int a , int b ) {    Gr[++T].y = b , Gr[T].l = h[a] , h[a] = T ;    Gr[++T].y = a , Gr[T].l = h[b] , h[b] = T ;}void Ndfs( int po ) {    int k , ori ;    dfn[po] = low[po] = ++time ;    sta[++top] = po ;    int ss = 0 ;    for( k=g[po] ; k ; k=f[k].l ) if( f[k].y != fa[po] ) {        ori = Gt ;        int anori = top ;        if( dfn[ f[k].y ] == 0 ) {            fa[ f[k].y ] = po ;            ss++ ;            Ndfs( f[k].y ) ;            if( low[ f[k].y ] >= dfn[po] ) {                while( anori != top ) {                    Ntid[ sta[ top ] ] = f[k].y ;                    top -- ;                }                while( Gt>ori ) {                    Gins( f[k].y , Gsta[Gt].obj ) ;                    Br_info pp ;                    pp.a = f[k].y , pp.b = Gsta[Gt].obj ;                    Bri_info[ Gsta[Gt].bridge ].psb( pp ) ;                    Gt-- ;                }                Gsta[ ++Gt ].obj = f[k].y , Gsta[ Gt ].bridge = po ;            }        }        low[po] = min( low[po] , low[ f[k].y ] ) ;    }    if( po==1 ) {        Ntid[1] = Gsta[1].obj ;        for( k=Gt ; k>1 ; k-- ) {            Gins( Gsta[1].obj , Gsta[k].obj ) ;            Br_info pp ;            pp.a = Gsta[1].obj, pp.b = Gsta[k].obj ;            Bri_info[ Gsta[k].bridge ].psb( pp ) ;        }    } }int l[32][N] , inx[32] ;void Pre( int po ) {    for( int k = 1 ; inx[k]<=de[po] ; k++ ) l[k][po] = l[k-1][ l[k-1][po] ] ;    for( int k = h[po] ; k ; k = Gr[k].l ) if( Gr[k].y != l[0][po] ) {            de[ Gr[k].y ] = de[po] + 1 ;            l[0][ Gr[k].y ] = po ;            Pre( Gr[k].y ) ;    }}int LCA( int a , int b ) {    if( de[a] > de[b] ) swap( a,b ) ;    for( int sub = de[b] - de[a] , j=0 ; sub ; j++,sub/=2 ) if( sub % 2 ) {        b = l[j][b] ;    }    if( a==b ) return a ;    int i  ;    for( i=0 ; i>=0 ; ) {        for( i=30 ; i>=0 ; i-- ) if( l[i][a]!=l[i][b] ) {            a = l[i][a] , b = l[i][b] ;            break ;        }    }    return l[0][a] ;}bool Test( Br_info pp , int lca , int a ) {    if( LCA( a , pp.a ) != pp.a ) return 0 ;    if( LCA( a , pp.b ) != pp.b ) return 0 ;    if( LCA( lca , pp.a ) !=lca ) return 0 ;    if( LCA( lca , pp.b ) !=lca ) return 0 ;    return 1 ;}int Esta[N] , Et , e[N] ;void Eins( int a , int b ) {    Er[++T].y = b , Er[T].l = e[a] , e[a] = T ;    Er[++T].y = a , Er[T].l = e[b] , e[b] = T ;}void Edfs( int po ) {    int k , ori ;    dfn[po] = low[po] = ++ time ;    sta[ ++top ] = po ;    for( k=g[po] ; k ; k=f[k].l ) if( fa[po] != f[k].y ) {        ori = Et ;        int anori = top ;        if( dfn[ f[k].y ] == 0 ) {            Edfs( f[k].y ) ;        }        low[po] = min( low[ f[k].y ] , low[po] ) ;        if( low[ f[k].y ] > dfn[po] ) {            while( top!=anori ) {                Etid[ sta[top--] ] = f[k].y ;            }            while( Et!=ori ) {                Eins( Esta[Et--] , f[k].y ) ;            }            Esta[ ++Et ] = f[k].y ;        }       }    if( po==1 ) {        while( top ) Etid[ sta[top--] ] =  1;        while( Et!=0 ) Eins( Esta[ Et-- ] , 1 ) ;    }}int El[32][N] , Ede[N] ;int ELCA( int a , int b ) {    if( Ede[a] > Ede[b] ) swap( a,b ) ;    for( int sub = Ede[b] - Ede[a] , j=0 ; sub ; j++,sub/=2 ) if( sub % 2 ) {        b = El[j][b] ;    }    if( a==b ) return a ;    int i  ;    for( i=0 ; i>=0 ; ) {        for( i=30 ; i>=0 ; i-- ) if( El[i][a]!=El[i][b] ) {            a = El[i][a] , b = El[i][b] ;            break ;        }    }    return El[0][a] ;}void Epre( int po ) {    for( int k = 1 ; inx[k]<=Ede[po] ; k++ ) El[k][po] = El[k-1][ El[k-1][po] ] ;    for( int k = e[po] ; k ; k = Er[k].l ) if( Er[k].y != El[0][po] ) {            Ede[ Er[k].y ] = Ede[po] + 1 ;            El[0][ Er[k].y ] = po ;            Epre( Er[k].y ) ;    }}int main() {    for( i=1 , inx[0]=1 ; i<=30 ; i++ ) inx[i] = inx[i-1] * 2 ;    scanf("%d%d",&n,&m ) ;    for( i=1 ; i<=m ; i++ ) {        int a , b ;        scanf("%d%d",&a,&b ) ;        ins( a , b ) , ins( b , a ) ;    }    T = 0 ;    Ndfs( 1 ) ;    memset( dfn , 0 , sizeof dfn ) ;    memset( low , 0 , sizeof low ) ;    time = 0 ;    top = 0 ;    T = 0 ;    Edfs( 1 ) ;    Pre( Gsta[1].obj ) ;    Epre( 1 ) ;    scanf("%d",&Q ) ;    while( Q-- ) {        int typ ;        scanf("%d",&typ ) ;         if( typ==2 ) {            int A , B , C ;            scanf("%d%d%d",&A,&B,&C ) ;            A = Ntid[A] , B = Ntid[B] ;            int lca = LCA( A , B ) ;            bool jud = 0 ;            for( iter it = Bri_info[C].begin() ; it!=Bri_info[C].end() ; it++ ) {                Br_info pp = *it ;                if( Test( pp , lca , A ) || Test( pp , lca , B ) ) {                    jud = 1 ;                    break ;                 }            }            if( jud ) puts("no" ) ; else puts("yes" ) ;        } else {            int C[2] , A , B ;            scanf("%d%d%d%d",&A,&B,&C[0],&C[1] ) ;            A = Etid[A] , B = Etid[B] , C[0] = Etid[ C[0] ] , C[1] = Etid[ C[1] ] ;            if( C[1]==C[0] ) {                puts("yes" ) ;                continue ;            }            if( ELCA( C[1] , C[0] ) == C[0] ) swap( C[1] , C[0] ) ;// C[0] is the lower one             if( ELCA( A , C[0] ) == C[0] && ELCA( C[0] , B ) != C[0] || ELCA( B , C[0] ) == C[0] && ELCA( C[0] , A ) != C[0] ) puts("no" ) ;                else puts("yes" ) ;        }    }}

DebugLog
用栈记录块的点时,ori=top的位置要放到找边循环内。

0 0
原创粉丝点击