题解
题意是给定一个
1
e
5
1e5
1e5的无向图(可自环可重边且联通度不为1),
1
e
5
1e5
1e5次询问
问是否存在两条没有公共边的路使得
v
v
v到
u
u
u,
w
w
w到
u
u
u成立
第一容易想到的点是边缩。边缩后满足同一节点中的 2 2 2个点必定有 2 2 2条路可达到
之后通过这性质可以发现假如 u u u与 v 、 w v、w v、w任意一个在同一节点答案必定是 Y e s Yes Yes
对于其他情况,我们又可以发现当求出这 3 3 3个点相互的 L C A LCA LCA时
- 假如 l c a ( u , v ) = u lca(u,v)=u lca(u,v)=u ,只要满足 l c a ( u , w ) = = l c a ( v , w ) lca(u,w)==lca(v,w) lca(u,w)==lca(v,w)则是 Y e s Yes Yes
- 同理假如 l c a ( u , w ) = u lca(u,w)=u lca(u,w)=u,只要满足 l c a ( u , v ) = = l c a ( v , w ) lca(u,v)==lca(v,w) lca(u,v)==lca(v,w)则是 Y e s Yes Yes
- 否则 必定时No
(注意):缩点后可能会是森林,需要注意不在同一棵树上的情况
复杂度为O(nlogn)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <cmath>
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e5+7,M=2e6;
int head[N],NEXT[M],ver[M],tot,dcc;
int Head[N],Next[M],VER[M],TOT,t;
int n,m,ppp[N],cnt;
int low[N],dfn[N],c[N],d[N],dist[N];
int f[N][50];
bool bridge[M],vis[N];
queue<int>q;
int num;
void link(int u,int v){
ver[++tot]=v;
NEXT[tot]=head[u];
head[u]=tot;
}
void Link(int u,int v){
VER[++TOT]=v;
Next[TOT]=Head[u];
Head[u]=TOT;
// cout<<u<<' '<<v<<endl;
}
void init(){
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++) {
head[i]=0;
Head[i]=0;
low[i]=dfn[i]=d[i]=dist[i]=0;
c[i]=0;
vis[i]=false;
}
for(int i=1;i<=n;i++){
for(int j=0;j<50;j++) f[i][j]=0;
}
num=0;
tot=1,dcc=0,TOT=1;
}
void tarjan(int x,int pre){
low[x]=dfn[x]=++num;
ppp[x]=cnt;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
if(!dfn[y]){
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x]){
bridge[i]=bridge[i^1]=true;
}
}
else if(i!=(pre^1))
low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x){
c[x]=dcc;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
if(c[y]||bridge[i]) continue;
dfs(y);
}
}
void DFS(int x){
vis[x]=true;
for(int i=head[x];i;i=NEXT[i]){
int y=ver[i];
if(vis[y]) continue;
if(bridge[i]){
Link(c[x],c[y]);
Link(c[y],c[x]);
bridge[i]=bridge[i^1]=false;
}
DFS(y);
}
}
void bfs(){
while(q.size()){
int x=q.front();
q.pop();
for(int i=Head[x];i;i=Next[i]){
int y=VER[i];
if(d[y]) continue;
d[y]=d[x]+1;
dist[y]=dist[x]+1;
f[y][0]=x;
for(int j=1;j<=t;j++){
f[y][j]=f[f[y][j-1]][j-1];
}
q.push(y);
}
}
}
int lca(int x,int y){
if(d[x]>d[y]) swap(x,y);
for(int i=t;i>=0;i--){
if(d[f[y][i]]>=d[x]) y=f[y][i];
}
if(x==y) return x;
for(int i=t;i>=0;i--){
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
}
return f[x][0];
}
int main(){
//freopen("h.txt","r",stdin);
int T;
int Q;
int u,v,w;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&Q);
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
link(u,v);
link(v,u);
}
cnt=0;
for(int i=1;i<=n;i++){
cnt++;
if(!dfn[i]){
tarjan(i,0);
}
}
for(int i=1;i<=n;i++){
if(!c[i]){
++dcc;
dfs(i);
}
}
// for(int i=1;i<=n;i++) cout<<c[i]<<' ';
// cout<<endl;
for(int i=1;i<=n;i++) {
if(!vis[i]){
DFS(i);
d[c[i]]=1;
q.push(c[i]);
}
}
t=(int)(log(n)/log(2))+1;
bfs();
while(Q--){
scanf("%d%d%d",&u,&v,&w);
int res1,res2,res3;
res1=lca(c[u],c[v]);
res2=lca(c[v],c[w]);
res3=lca(c[u],c[w]);
// cout<<res1<<' '<<res2<<' '<<res3<<endl;
if(ppp[u]!=ppp[v]||ppp[u]!=ppp[w]||ppp[v]!=ppp[w]){
puts("No");
continue;
}
if(c[u]==c[v]||c[u]==c[w]){
puts("Yes");
continue;
}
else if(c[v]==c[w]&&c[v]!=c[u]){
puts("No");
continue;
}
if(res1==c[u]){
if(res2==res3) puts("Yes");
else puts("No");
}
else if(res3==c[u]){
if(res1==res2) puts("Yes");
else puts("No");
}
else puts("No");
}
}
return 0;
}