说在前面
啊啊啊me热死了QAQ
UPD:热到me的酸奶都变稀了QAQ
题目
BZOJ2140传送门
看题可戳传送门
解法
me被卡Hash了
而且被卡了一版!!!27,55,233,137等等均被卡
最后用131过掉了…
解法可以参见2015国家集训队论文:长郡中学陈胤伯的《浅谈图的匹配算法及其应用》
匹配边从左向右连,非匹配边从右向左连,然后跑tarjan
如果一对匹配点在同一个SCC里,说明是不稳定的(因为二分图的环都是偶环,把所有匹配边逆时针转一条边,形成新的匹配,且匹配数与原来相等)
下面是Base为131的代码
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const int Base = 131 ;
int N , M , id_c , head[8005] , tp ;
map<long long,int> id ;
struct Path{
int pre , to ;
}p[30005] ;
pair<int,int> mar[4006] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
}
int getID( char *s ){
int len = strlen( s ) ;
long long rt = 0 , t = 1 ;
for( int i = 0 ; i < len ; i ++ )
rt += t * s[i] , t *= Base ;
if( !id[rt] ) id[rt] = ++id_c ;
return id[rt] ;
}
int dfn[8005] , dfs_c , sta[8005] , topp , scc[8005] , scc_cnt ;
int dfs( int u ){
int lowu = dfn[u] = ++dfs_c ;
sta[++topp] = u ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( !dfn[v] ) lowu = min( lowu , dfs( v ) ) ;
else if( !scc[v] ) lowu = min( lowu , dfn[v] ) ;
} if( lowu == dfn[u] ){
scc_cnt ++ ;
while( true ){
int x = sta[topp--] ;
scc[x] = scc_cnt ;
if( x == u ) break ;
}
} return lowu ;
}
void solve(){
for( int i = 1 ; i <= id_c ; i ++ )
if( !dfn[i] ) dfs( i ) ;
for( int i = 1 ; i <= N ; i ++ )
puts( scc[ mar[i].first ] == scc[ mar[i].second ] ? "Unsafe" : "Safe" ) ;
}
int main(){
scanf( "%d" , &N ) ;
char s1[10] , s2[10] ;
for( int i = 1 ; i <= N ; i ++ ){
scanf( "%s%s" , s1 , s2 ) ;
int u = getID( s1 ) , v = getID( s2 ) ;
In( u , v ) , mar[i] = make_pair( u , v ) ;
} scanf( "%d" , &M ) ;
for( int i = 1 ; i <= M ; i ++ ){
scanf( "%s%s" , s1 , s2 ) ;
int u = getID( s1 ) , v = getID( s2 ) ;
In( v , u ) ;
} solve() ;
}