题意:
给一个连通的无向图,有两种询问:
- a,b,c,d 问如果删掉c,d之间的边,a,b之间是否还连通
- a,b,c 问如果删掉顶点c,a,b之间是否还连通
分析:
考虑第一种查询
- 设c是d的儿子节点,如果c,d之间是一个桥并且a,b两个节点一个在c的子树中一个不在,这种情况下是不连通的。其他情况都是连通的。
考虑第二种查询
分成三种情况讨论:
- 1.a,b都在子树c中,如果a,b在c的同一个儿子子树中那么去掉c是连通的。否则,让a,b往上跳,变成c的两个儿子。如果low(a)≥pre(c)或low(b)≥pre(c)有一个成立,那么是不连通的。
- 2.a,b只有一个在子树c中,由于对称性,不妨假设a在子树c中。同样让a往上跳,变成c的儿子。如果low(a)≥pre(c)那么不连通,否则连通。
- 3.a,b都不在子树c中,那么去掉c完全没有任何影响,所以还是连通的。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
int head[maxn],tot;
int dfn[maxn],low[maxn],index;
int fa[maxn][20],dep[maxn],out[maxn];
bool vis[maxm];
void init(){
memset(head,-1,sizeof head);
tot=0;
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
index=0;
memset(dep,0,sizeof dep);
memset(vis,0,sizeof vis);
memset(out,0,sizeof vis);
}
struct node{
int to,next;
}edge[maxm];
void addedge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void tarjan(int u,int deep){
low[u]=dfn[u]=++index;
dep[u]=deep;
for(int i=head[u];i!=-1;i=edge[i].next){
if(vis[i]) continue;
vis[i]=vis[i^1]=1;
int v=edge[i].to;
if(!dfn[v]){
tarjan(v,deep+1);
fa[v][0]=u;
low[u]=min(low[u],low[v]);
}else low[u]=min(dfn[v],low[u]);
}
out[u]=index;
}
bool judge1(int a,int b,int c,int d){
if(dep[c]<dep[d]){
swap(c,d);
}
bool ina=0,inb=0;
if(dfn[a]>=dfn[c]&&out[a]<=out[c]) ina=1;
if(dfn[b]>=dfn[c]&&out[b]<=out[c]) inb=1;
if((ina&&inb)||(!ina&&!inb)) return 1;
else{
if(low[c]<=dfn[d]) return 1;
return 0;
}
}
int move(int x,int step){
if(step<0) return -1;
for(int i=19;i>=0;i--){
if((1<<i)&step) x=fa[x][i];
}
return x;
}
bool judge2(int a,int b,int c){
bool ina=0,inb=0;
if(dfn[a]>=dfn[c]&&out[a]<=out[c]) ina=1;
if(dfn[b]>=dfn[c]&&out[b]<=out[c]) inb=1;
bool flag=0;
if(!ina&&!inb) flag=1;
else if(ina&&!inb){
int p=move(a,dep[a]-dep[c]-1);
if(p!=-1&&low[p]<dfn[c]) flag=1;
}else if(!ina&inb){
int p=move(b,dep[b]-dep[c]-1);
if(p!=-1&&low[p]<dfn[c]) flag=1;
}else{
int p=move(a,dep[a]-dep[c]-1);
int q=move(b,dep[b]-dep[c]-1);
if(p==q) flag=1;
else if(low[p]<dfn[c]&&low[q]<dfn[c]) flag=1;
}
return flag;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
init();
while(m--){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i,0);
}
for(int i=1;i<20;i++){
for(int j=1;j<=n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
int q;
scanf("%d",&q);
while(q--){
int op,a,b,c,d;
scanf("%d",&op);
if(op==1){
scanf("%d%d%d%d",&a,&b,&c,&d);
if(judge1(a,b,c,d)) printf("yes\n");
else printf("no\n");
}else {
scanf("%d%d%d",&a,&b,&c);
if(judge2(a,b,c)) printf("yes\n");
else printf("no\n");
}
}
}
return 0;
}