题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5986
题意
n个点, m条边的图,询问 z,x,y,是否能找到 x到 z, y到 z没有重复经过路的方案。
题解
边双联通,进行缩点,然后用LCA判断。
代码
#include<bits/stdc++.h>
#define N 300010
#define INF 0x3f3f3f3f
#define eps 1e-10
// #define pi 3.141592653589793
// #define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pi;
int n,m,dfs_time,cnt,top;
vector<int> a[N],b[N];
int dfn[N],low[N],col[N],d[N]; bool f[N<<1],v[N];
int Stack[N];
void Tarjan(int u, int fa) {
dfn[u] = low[u] = ++dfs_time;
Stack[top++] = u;
int k = 0,v;
for (auto v:a[u]) {
if (v == fa && !k) {
k ++;
continue;
}
if (!low[v]) {
Tarjan(v, u);
low[u] = min(low[u], low[v]);
} else low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
cnt++;
do {
v = Stack[--top];
d[v] = cnt;
} while (u != v);
}
}
int L[N],fa[N],anc[23][N],rt[N],tt;
void lable(int x,int ffa,int p){
rt[x]=tt;
for (auto i:b[x]) if (i!=ffa) {
fa[i]=x;
L[i]=p+1;
lable(i,x,p+1);
}
}
void preprocess()
{
for (int i=1;i<=cnt;i++) {
anc[0][i]=fa[i];
for (int j=1;(1<<j)<=cnt;j++) anc[j][i]=-1;
}
for (int j=1;(1<<j)<=cnt;j++)
for (int i=1;i<=cnt;i++)
if (anc[j-1][i]!=-1) anc[j][i]=anc[j-1][anc[j-1][i]];
}
int query(int p,int q)
{
int log;
if (L[p]<L[q]) swap(p,q);
for (log=1;(1<<log)<=L[p];log++); log--;
for (int i=log;i>=0;i--)
if (L[p]-(1<<i)>=L[q]) p=anc[i][p];
if (p==q)return p; //LCA为p
for (int i=log;i>=0;i--)
if (anc[i][p]!=-1 && anc[i][p]!=anc[i][q])
p=anc[i][p],q=anc[i][q];
return fa[p];//LCA为fa[p]
}
int main()
{
int T,q;
sc(T);
while(T--){
sccc(n,m,q);
for (int i=1;i<=n;i++){
a[i].clear(); b[i].clear();
dfn[i]=low[i]=col[i]=rt[i]=v[i]=0;
}for (int i=1;i<=m;i++) f[i]=0;
for (int x,y,i=1;i<=m;i++){
scc(x,y);
a[x].pb(y); a[y].pb(x);
}
cnt=0;
for (int i=1;i<=n;i++) if (!dfn[i]){
dfs_time=0;
Tarjan(i,-1);
}
for (int i=1;i<=n;i++) for (auto j:a[i]) if (d[i]!=d[j])
b[d[i]].pb(d[j]);
tt=0;
for (int i=1;i<=cnt;i++) if(!rt[i]){
tt++;
lable(i,-1,0);
}
preprocess();
while(q--){
int x,y,z;
sccc(z,x,y);
z=d[z];x=d[x];y=d[y];
if (!(rt[z]==rt[x] && rt[z]==rt[y])){
puts("No");continue;
}
if (z==x || z==y) puts("Yes");else
if (x==y) puts("No");else{
int t1=query(z,x),t2=query(z,y),f1,f2;
f1=(t1!=z); f2=(t2!=z);
if (f1!=f2) puts("Yes");else
if (f1 && f2)puts("No");else
if (query(x,y)==z) puts("Yes");else
puts("No");
}
}
}
}