1 //#pragma comment(linker, "/STACK:65536000") 2 #include <iostream> 3 #include <stdio.h> 4 #include <string.h> 5 #include <vector> 6 #include <map> 7 #include <math.h> 8 #include <queue> 9 #include <set> 10 #include <algorithm> 11 #define clr(a,b) memset(a,b,sizeof(a)) 12 #define mpr(a,b) make_pair(a,b) 13 #define ll long long 14 #define eps 1e-6 15 using namespace std; 16 17 const int N=100005,M=300005; 18 19 /* 20 * HDU4674 21 * 一个无向图,每个点最多只属于一个简单环,询问从a到b的简单路径能不能路过c 22 * 离线处理,先缩点,假设缩点完后a为A,b为B,c为C 23 * 对每个询问分别求出lca(A,B),lca(A,C),lca(B,C) 24 * 还要判断两个点求lca的时候,对lca的那个点,进出的联通块分别是哪个点,这个 25 * 在做完一边lca后再dfs一边就好了 26 * come记录从父亲节点进入这个联通块的是哪个点 27 * out数组在dfs中记录当前祖先的状态 28 * gra数组用来缩点建图,first保存连到下一个联通块的编号, 29 second保存从该联通块该边连出去的是哪个点 30 * qu数组用来lca询问 31 * tlca记录每个lca的值 32 * pt表示两个点连到lca的时候,进出lca那个联通块的点,-1说明就在lca上 33 */ 34 int n,m,q,eid,id,now,top; 35 int head[N],ed[M],nxt[M]; 36 int dfn[N],low[N],gid[N]; 37 int sta[N],block[N]; 38 vector<pair<int,int> >gra[N],qu[N]; 39 int f[N],vis[N],come[N],out[N],fa[N]; 40 int tlca[3*N],pt[3*N][2]; 41 int aa[N],bb[N],cc[N]; 42 43 int findfa(int s){return s==fa[s]?s:fa[s]=findfa(fa[s]);} 44 45 void addedge(int s,int e){ 46 ed[eid]=e;nxt[eid]=head[s];head[s]=eid++; 47 } 48 49 void tarjan(int s,int f,int b){ 50 dfn[s]=low[s]=++now; 51 sta[top++]=s;block[s]=b; 52 for(int i=head[s];~i;i=nxt[i]){ 53 int e=ed[i]; 54 if(i==f||i==(f^1))continue; 55 if(!dfn[e]){ 56 tarjan(e,i,b); 57 low[s]=min(low[s],low[e]); 58 }else 59 low[s]=min(low[s],dfn[e]); 60 } 61 if(low[s]==dfn[s]){ 62 id++; 63 while(top){ 64 int k=sta[--top]; 65 gid[k]=id; 66 if(k==s)return ; 67 } 68 } 69 } 70 71 void lca(int s,int f){ 72 fa[s]=s; 73 for(int i=0;i<(int)gra[s].size();i++){ 74 int e=gra[s][i].first; 75 if(e==f)continue; 76 lca(e,s); 77 fa[findfa(e)]=s; 78 } 79 vis[s]=1; 80 for(int i=0;i<(int)qu[s].size();i++){ 81 int e=qu[s][i].first,d=qu[s][i].second; 82 if(vis[e])tlca[d]=findfa(e); 83 } 84 } 85 86 void dfs(int s,int f){ 87 for(int i=0;i<(int)qu[s].size();i++){ 88 int d=qu[s][i].second; 89 int k=(tlca[d]==s)?-1:out[tlca[d]]; 90 if(~pt[d][0])pt[d][1]=k; 91 else pt[d][0]=k; 92 } 93 for(int i=0;i<(int)gra[s].size();i++){ 94 int e=gra[s][i].first,g=gra[s][i].second; 95 if(e==f){ 96 come[s]=g;continue; 97 } 98 out[s]=g; 99 dfs(e,s); 100 } 101 } 102 103 int main(){ 104 // freopen("/home/axorb/in","r",stdin); 105 while(~scanf("%d%d",&n,&m)){ 106 eid=0;clr(head,-1); 107 for(int i=0;i<m;i++){ 108 int a,b;scanf("%d%d",&a,&b); 109 addedge(a,b);addedge(b,a); 110 } 111 id=now=top=0; 112 for(int i=1;i<=n;i++)dfn[i]=0; 113 int cnt=0; 114 for(int i=1;i<=n;i++) 115 if(!dfn[i])tarjan(i,-1,++cnt); 116 for(int i=1;i<=id;i++){ 117 gra[i].clear();qu[i].clear(); 118 } 119 for(int i=1;i<=n;i++) 120 for(int j=head[i];~j;j=nxt[j]){ 121 int s=gid[i],e=gid[ed[j]]; 122 if(s!=e)gra[s].push_back(mpr(e,i)); 123 } 124 clr(f,0); 125 scanf("%d",&q); 126 for(int i=0;i<q;i++){ 127 int a,b,c;scanf("%d%d%d",&a,&b,&c); 128 //如果3个点不能到达,则答案肯定否定 129 if(block[a]!=block[b]){f[i]=1;continue;} 130 if(block[b]!=block[c]){f[i]=1;continue;} 131 if(block[a]!=block[c]){f[i]=1;continue;} 132 //如果起点和终点相同,那个路过的点也必须相同 133 if(a==b&&a!=c){f[i]=1;continue;} 134 int s=gid[a],e=gid[b],k=gid[c]; 135 qu[s].push_back(mpr(e,i*3)); 136 qu[e].push_back(mpr(s,i*3)); 137 qu[s].push_back(mpr(k,i*3+1)); 138 qu[k].push_back(mpr(s,i*3+1)); 139 qu[e].push_back(mpr(k,i*3+2)); 140 qu[k].push_back(mpr(e,i*3+2)); 141 aa[i]=a;bb[i]=b;cc[i]=c; 142 } 143 for(int i=1;i<=id;i++)vis[i]=0; 144 for(int i=0;i<q*3;i++) 145 pt[i][0]=pt[i][1]=-1; 146 for(int i=1;i<=id;i++) 147 if(!vis[i]){ 148 lca(i,-1); 149 dfs(i,-1); 150 } 151 for(int i=0;i<q;i++){ 152 if(f[i]){ 153 puts("No");continue; 154 } 155 if(gid[aa[i]]==gid[bb[i]]){//如果A=B,那个C必须等于A 156 if(gid[cc[i]]==gid[aa[i]])puts("Yes"); 157 else puts("No"); 158 } 159 else if(gid[cc[i]]==tlca[i*3]){//如果C是lca(A,B) 160 if(pt[i*3][1]==-1){ 161 //如果AB中有一个等于C,那么当那个点是出口且C不是出口的时候,C就不能到达 162 int k=(gid[aa[i]]==gid[cc[i]])?aa[i]:bb[i]; 163 if(k==pt[i*3][0]&&cc[i]!=k) puts("No"); 164 else puts("Yes"); 165 }else{ 166 //如果AB都不是C,那个当AB进出C的是同一个点且不是C,C就不能到达 167 if(pt[i*3][0]==pt[i*3][1]&&cc[i]!=pt[i*3][0]) puts("No"); 168 else puts("Yes"); 169 } 170 }else if(tlca[i*3+1]==gid[cc[i]]&&tlca[i*3+2]==tlca[i*3]){ 171 //如果C是A的祖先,且lca(A,B)=lca(C,B) 172 //那么当父亲到C的点和C连出去到A的点是同一个点且不是C,那个C就不能到达 173 int k=(pt[i*3+1][0]==-1)?aa[i]:pt[i*3+1][0]; 174 if(come[gid[cc[i]]]==k&&k!=cc[i])puts("No"); 175 else puts("Yes"); 176 }else if(tlca[i*3+2]==gid[cc[i]]&&tlca[i*3+1]==tlca[i*3]){ 177 //同上 178 int k=(pt[i*3+2][0]==-1)?bb[i]:pt[i*3+2][0]; 179 if(come[gid[cc[i]]]==k&&k!=cc[i])puts("No"); 180 else puts("Yes"); 181 }else puts("No"); 182 } 183 } 184 }