第八篇:P1407
题解补完计划:第八篇
我们考虑结婚的 \(G\) 向 \(B\) 连边, 对于曾经喜欢了的我们考虑 \(B\) 向 \(G\),那么,如果有环,那一定是一个偶数环且是 \(GBGBGBGBGB\) 排列的(没有给给和拉拉,可惜可惜)。那么如果一对夫妻在同一个联通块里,那么是肯定可以出轨的,那如果不在一个联通块呢,我们发现如果他们两个不在一个联通块里面,就一定不行,因为连向 \(B\) 的一定是 \(G\),连向 \(G\) 的一定是 \(B\),如果存在一对人可以出轨那么就一定至少存在一个人不能组合,所以接下来就好做了,我们只需要用 Tarjan 缩联通块,然后判断就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 80005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
map<string, intl> mp;
intl n,m,idx;
string id[N];
vector<intl> g[N];
intl scc, dfn[N], low[N], tot, vis[N], sta[N], top, belong[N];
void tj(intl u,intl fath) {
dfn[u] = low[u] = ++ tot;
sta[++top] = u, vis[u] = 1;
for(auto v:g[u]) {
// if(v == fath) continue;
if(!dfn[v]) tj(v,u), low[u] = min(low[v],low[u]);
else if(vis[v]) low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u]) {
intl v;scc++;
do {
v = sta[top--];
vis[v] = 0;
belong[v] = scc;
}while(u != v);
}
}
pair<string,string> a[N];
int main() {
n = read();
For(i, 1, n) {
string B,G;cin >> G >> B;
if(!mp[B]) mp[B] = ++idx, id[idx] = B;
if(!mp[G]) mp[G] = ++idx, id[idx] = G;
g[mp[G]].push_back(mp[B]);
a[i]={G,B};
}
m = read();
For(i, 1, m) {
string B,G;cin >> G >> B;
g[mp[B]].push_back(mp[G]);
}
For(i, 1, 2*n) if(!dfn[i]) tj(i,0);
For(i, 1, n) {
if(belong[mp[a[i].first]] == belong[mp[a[i].second]]) puts("Unsafe");
else puts("Safe");
}
return 0;
}
/*
5
A a
B b
C c
D c
F f
5
B a
C b
F b
D d
A f
*/

浙公网安备 33010602011771号