追捕盗贼
来源:互联网 发布: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的位置要放到找边循环内。
- 追捕盗贼
- 【COCI 2007】追捕盗贼
- NOI2007.Day2.T3.追捕盗贼
- 【基于贪心的树型动态规划】【NOI2007】追捕盗贼
- 追捕
- 完美盗贼
- 职业指南:盗贼[Rogue]
- [盗贼]经典PK
- 盗贼分宝石
- Leetcode337. 盗贼问题
- Astar - 复赛 5.追捕
- 追捕oicq探测技术
- 追捕者v1.0
- NKOJ-4239 追捕游戏
- 追捕游戏 LCA
- nkoj 4239 追捕游戏
- P4239追捕游戏
- 盗贼开锁技能问题(详细)
- 使用weibo js,新浪微博三方登陆,帐号绑定。
- poj 3907 求多边形面积
- viewpager禁用左右滑动和去掉中间的切换页面
- 数据库索引的作用和优点缺点
- 函数回调以及函数指针
- 追捕盗贼
- 粗略地在iOS中使用URLManager架构
- Hibernate一对一外键双向关联(xml配置篇)
- MFC多语言实现方法
- [HDU 1024] Max Sum Plus Plus 多段子序列和
- 最近发现的一款普通牌分析仪
- linux结束进程步骤
- Qt之QDesktopServices
- 初学git:用git bash往github push代码