/* 题目: 有n种物品,现给出m种关系,每种关系a,b对应着物品b能够用物品a来换,然后有q个询问(a,b), 问物品a能不能换到物品b。 分析: 如果直接dfs求传递闭包的话,会超时的。我们可以重新建图,使得图中没有环,即把强连通分支 变成缩点后用邻接表重新建图,然后dfs求传递闭包即可 */ #include <cstdio> #include <vector> #include <cstring> #include <iostream> using namespace std; const int X = 5005; int dfn[X],father[X],low[X],stack[X],depth,top,bcnt; int n,m,t; bool instack[X]; bool map[1005][1005]; //新图中的关系 vector<int> adj[X]; //旧图 vector<int> nadj[X]; //新图 void tarjan(int u) //tarjan算法求强连通分支 { int len,v; low[u] = dfn[u] = ++depth; stack[++top] = u; instack[u] = true; len = adj[u].size(); for(int i=0;i<len;i++) { v = adj[u][i]; if(!low[v]) { tarjan(v); low[u] = min(low[u],low[v]); } else if(instack[v]) low[u] = min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ++bcnt; do { v = stack[top--]; instack[v] = false; father[v] = bcnt; }while(u!=v); } } void solve() { depth = top = bcnt = 0; memset(instack,false,sizeof(instack)); memset(low,0,sizeof(low)); memset(map,false,sizeof(map)); for(int i=1;i<=n;i++) if(!low[i]) tarjan(i); int len,v; for(int u=1;u<=n;u++) //重新建图 { len = adj[u].size(); for(int j=0;j<len;j++) { v = adj[u][j]; if(father[u]!=father[v])//father记录的是在新图中的顶点号(所在缩点的号码) nadj[father[u]].push_back(father[v]); } } } void dfs(int u,int v) //dfs求传递闭包,若用floyd的话会超时 { int len = nadj[v].size(); for(int i=0;i<len;i++) dfs(u,nadj[v][i]); map[u][v] = true; } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); int u,v; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) //初始化 { adj[i].clear(); nadj[i].clear(); } for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); adj[u].push_back(v); } solve(); for(int i=1;i<=bcnt;i++) //求传递闭包 dfs(i,i); scanf("%d",&t); while(t--) { scanf("%d%d",&u,&v); if(father[u]==father[v]) { printf("Yes\n"); continue; } if(map[father[u]][father[v]]) printf("Yes\n"); else printf("No\n"); } } return 0; }