Description
为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统。警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N。
警察经常想在罪犯从一个城市逃亡另一个城市的过程中抓住他。侦查员在仔细研究地图,以决定在哪个城市设置障碍,或者断掉某条路。你的计算机系统必须回答以下两种问题:
1、 如果连接城市G1和G2的路被封掉,罪犯能否从城市A逃到城市B?
2、 如果城市C被封掉,罪犯能否从城市A逃到城市B?
编程实现上述计算机系统。
Input
输入第一行包含两个整数N和E(2<=N<=100000,1<=E<=500000),表示城市和边的数量。
接下来E行,每行包含两个不同的整数Ai和Bi,表示城市Ai和Bi之间有一条边直接相连,任意两个城市之间最多只有一条边相连。
接下来一行包含一个整数Q(1<=Q<=300000),表示询问次数。
接下来Q行,每行包含4个或5个整数,第一个数为1或2,表示询问问题的种类。
如果问题种类是1,后面跟着4个整数A,B,G1,G2,如上描述表示询问如果G1和G2之间的路封掉罪犯能否从城市A逃到城市B,保证A和B不同,G1和G2之间一定存在路。
如果问题种类是2,后面跟着三个整数A,B,C,三个数互不相同,表示询问如果封掉城市C,罪犯能否从城市A逃到城市B。
输入数据保证一开始任意两个城市都可以相互到达。
Output
每个询问输出一行“yes”或“no”。
Sample Input
13 15
1 2
2 3
3 5
2 4
4 6
2 6
1 4
1 7
7 8
7 9
7 10
8 11
8 12
9 12
12 13
5
1 5 13 1 2
1 6 2 1 4
1 13 6 7 8
2 13 6 7
2 13 6 8
Sample Output
yes
yes
yes
no
yes
其实分开来搞不难……
先Tarjan缩环(无向图强连通分量,每次走过一条边就不走其反向边),之后如果删的边在一个强连通分量里面,那就不会有影响。
否则用dfs序判一下
在Tarjan的dfs树上搞。
如果c能影响到a~b的点,那么c一定在a~b的路径上,或者c是a or b的祖先且ab的lca是c的祖先。
设该点到c的路径上最靠近c的点(就是c的儿子之一)为x
如果一个点在删掉c后还能连通,那么x的子树中一定有一个点能走返祖边到c的祖先。
然后判断low[x]和dfn[c]就行了。
#include
#include
#include
#include
#include
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a
using namespace std;
int a[1000002][3];
struct BB{int x,y,z;} b[1000002];
int ls[100001];
int Ls[100001];
int dfn[100001];
int low[100001];
int Dfn[100001][2];
int Df[100001][2];
int num[100001];
int fa[100001][17];
bool bz[100001];
bool Bz[500001];
int d[100001];
int D[100001];
int dp[100001];
int N,n,m,i,j,k,l,len,L,Q,s1,s2,s3,s4,s5,S;
void swap(int &x,int &y)
{
int z=x;
x=y;
y=z;
}
bool cmp(BB a,BB b) {return a.xvoid New(int x,int y)
{
len++;
a[len][0]=y;
a[len][1]=ls[x];
a[len][2]=x;
ls[x]=len;
}
void Read()
{
len=1;
scanf("%d%d",&n,&m);
fo(i,1,m)
{
scanf("%d%d",&j,&k);
New(j,k);New(k,j);
}
}
void tj(int t)
{
int i;
Df[t][0]=++S;
fo(i,1,16)
fa[t][i]=fa[fa[t][i-1]][i-1];
dfn[t]=++j;
low[t]=j;
d[++L]=t;
bz[t]=1;
for (i=ls[t]; i; i=a[i][1])
if (!Bz[i>>1])
{
Bz[i>>1]=1;
if (!dfn[a[i][0]])
{
fa[a[i][0]][0]=t;
dp[a[i][0]]=dp[t]+1;
tj(a[i][0]);
}
if (bz[a[i][0]]) low[t]=min(low[t],low[a[i][0]]);
Bz[i>>1]=0;
}
Df[t][1]=S;
if (dfn[t]==low[t])
{
k++;
for (; d[L+1]!=t; num[d[L--]]=k) bz[d[L]]=0;
}
}
void dfs(int t,int Fa)
{
Dfn[t][0]=++j;
for (int i=Ls[t]; i; i=b[i].z)
if (b[i].y!=Fa)
dfs(b[i].y,t);
Dfn[t][1]=j;
}
bool Inc(int x,int y) {return Dfn[x][0]<=Dfn[y][0] && Dfn[y][1]<=Dfn[x][1];}
bool inc(int x,int y) {return Df[x][0]<=Df[y][0] && Df[y][1]<=Df[x][1];}
int lca(int i,int j)
{
int k;
if (dp[i]for (k=16; dp[i]>dp[j]; i=(dp[fa[i][k]]>=dp[j])?fa[i][k]:i,k--);
fd(k,16,0) if (fa[i][k]!=fa[j][k]) i=fa[i][k],j=fa[j][k];
if (i!=j) i=fa[i][0];
return i;
}
bool pd(int s1,int s2)
{
int i,k;
if (inc(s2,s1))
{
for (k=16,i=s1; k>=0; i=(dp[fa[i][k]]>dp[s2])?fa[i][k]:i,k--);
if (low[i]>=dfn[s2])
{
printf("no\n");
return 1;
}
return 0;
} else return 0;
}
void Sort()
{
fo(i,2,len)
b[i].x=num[a[i][2]],b[i].y=num[a[i][0]];
stable_sort(b+2,b+len+1,cmp);
j=0;
k=len;
fo(i,2,len)
if (b[i].x!=b[i].y && (b[i].x!=b[i-1].x || b[i].y!=b[i-1].y))
{
j++;
b[j].x=b[i].x;
b[j].y=b[i].y;
b[j].z=Ls[b[j].x];
Ls[b[j].x]=j;
}
len=j;
}
void work1()
{
scanf("%d",&s5);
s2=num[s2];s3=num[s3];s4=num[s4];s5=num[s5];
if (!Inc(s4,s5)) swap(s4,s5);
if ((Inc(s5,s2) && !Inc(s5,s3) || !Inc(s5,s2) && Inc(s5,s3)) && s4!=s5)
printf("no\n"); else printf("yes\n");
}
void work2()
{
l=lca(s2,s3);
if (inc(s4,l) && s4!=l || !inc(s4,s2) && !inc(s4,s3)) printf("yes\n");
else
{
if (pd(s2,s4)) return;
if (pd(s3,s4)) return;
printf("yes\n");
}
}
void Tarjan()
{
j=0;L=0;k=0;
tj(1);
N=k;
}
int main()
{
Read();
Tarjan();
Sort();
j=0;dfs(1,0);
for (scanf("%d",&Q); Q; Q--)
{
scanf("%d%d%d%d",&s1,&s2,&s3,&s4);
if (s1==1) work1(); else work2();
}
return 0;
}