The railways and the rail-stations in TC are fragile and always meet with different kinds of problems. In order to reach the destination safely on time, you are asked to develop a system which has two types of main functions as below.
1: A B C D, reporting whether we can get from station A to station B without passing the railway that connects station C and station D.
2: A B C, reporting whether we can get from station A to station B without passing station C.
Please notice that the railways are UNDIRECTED.
The stations are always labeled from 1 to N.
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
yes yes yes no yes
吉林大学的一道题。当时比赛完全没想法。后来学了强连通双连通试着根据解题报告做下。结题报告如下:
给出一个无向图,询问两个点在删去一条边或者一个点以后能否到达。
生成一颗dfs树,然后记录dfn[]、low[]、final[]、deep[]。Final表示离开这个节点的时间。
对于边的询问,询问的节点是a,b,设这个边为g1-g2,其中deep[g1]>deep[g2]。
1. a在g1的子树内,b也在g1的子树内,那么a、b可以到达。
2. a不在g1的子树内,b也不在g1的子树内,那么a、b可以到达。
3. 不妨假设a在g1的子树内,b不在g1的子树内,则判断low[g1]是否≤dfn[g2]。如果是的话,那么a、b可以到达。
4. 其他情况下不能到达。
对于点的询问,询问的节点是a,b,设这个点为g1:
1. 如果a,b都不在g1的子树内。则可行
2. 如果a,b有一个在g1的子树内(设为a),求出在a-g1路径上的倒数第二个点k,如果low[k] < dfn[g1]则可行
3. 如果a,b都在g1的子树内。求出在a-g1路径上的倒数第二个点k1,在b-g1路径上的倒数第二个点k2,判断是否两者的low都<dfn[g1]则可行
4. 其他情况下不能到达。
如何判断一个点a是否在g的子树内:
Dfn[a] >= dfn[g] 且 final[a] <= final[g]
开始怎么都a不了。后然问了学长才发现对于点询问如果a,b,都在g1子树中,如果k1=k2那么直接输出yes好了。。wa了N多次。。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
int head[N],idx[N],ps[N],dfn[N],low[N];
struct rec
{
int v,link;
}edge[N*10];
int n,m,num,top,index,ans,nn;
bool vis[N*10];
int leave[N],deep[N],s,pre[N];
int sta[2][N*2],tp;
int f[N];
bool flag;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].link=head[u];
head[u]=num++;
edge[num].v=u;
edge[num].link=head[v];
head[v]=num++;
}
void DFS(int u,int dep)
{
int i,v;
tp=0;
sta[0][0]=u;
sta[1][0]=head[u];
dfn[u]=low[u]=++index;
ps[++top]=u;
deep[u]=dep;
pre[u]=-1;
f[u]=s;
while(1)
{
u=sta[0][tp];
i=sta[1][tp];
if(i)
{
sta[1][tp]=edge[i].link;
if(vis[i] || vis[i^1])
continue;
vis[i]=1;
v=edge[i].v;
if(dfn[v]==-1)
{
f[v]=s;
dfn[v]=low[v]=++index;
ps[++top]=v;
tp++;
sta[0][tp]=v;
sta[1][tp]=head[v];
pre[v]=u;
deep[v]=deep[u]+1;
}
else
if(idx[v]==-1)
{
if(low[u]>dfn[v])
low[u]=dfn[v];
}
}
else
{
leave[u]=index;
if(dfn[u]==low[u])
{
nn++;
v=-1;
while(v!=u)
{
v=ps[top--];
idx[v]=nn;
}
}
tp--;
if(tp<0)
break;
v=u;
u=pre[u];
if(low[u]>low[v])
low[u]=low[v];
}
}
}
void Trajan()
{
int i;
memset(dfn,-1,sizeof(dfn));
memset(idx,-1,sizeof(idx));
index=top=nn=0;
for(i=1;i<=n;i++)
{
s=i;
if(dfn[i]==-1)
{
DFS(i,1);
}
}
}
int main()
{
int u,v,k,q,g1,g2,tmp;
bool a,b;
while(~scanf("%d%d",&n,&m))
{
num=2;
memset(head,0,sizeof(head));
while(m--)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
memset(vis,0,sizeof(vis));
Trajan();
scanf("%d",&q);
while(q--)
{
scanf("%d",&k);
if(k==1)
{
scanf("%d%d%d%d",&u,&v,&g1,&g2);
if(f[u]!=f[v])
{
continue;
}
a=b=0;
if(deep[g1]<deep[g2])
tmp=g1,g1=g2,g2=tmp;
if(dfn[u]>=dfn[g1] && leave[u]<=leave[g1])
a=1;
if(dfn[v]>=dfn[g1] && leave[v]<=leave[g1])
b=1;
if((a && b) || (!a && !b))
{
puts("yes");
}
else
{
if(low[g1]<=dfn[g2])
puts("yes");
else
puts("no");
}
}
else
{
scanf("%d%d%d",&u,&v,&g1);
if(f[u]!=f[v])
{
continue;
}
if(u==g1 || v==g1)
{
puts("no");
continue;
}
a=b=0;
if(dfn[u]>=dfn[g1] && leave[u]<=leave[g1])
a=1;
if(dfn[v]>=dfn[g1] && leave[v]<=leave[g1])
b=1;
if(!a && !b)
{
puts("yes");
continue;
}
int x,y;
if(a && !b)
{
x=u;
while(pre[x]!=g1)
x=pre[x];
if(low[x]<dfn[g1])
puts("yes");
else
puts("no");
continue;
}
if(!a && b)
{
y=v;
while(pre[y]!=g1)
y=pre[y];
if(low[y]<dfn[g1])
puts("yes");
else
puts("no");
continue;
}
if(a && b)
{
x=u;
while(pre[x]!=g1)
x=pre[x];
y=v;
while(pre[y]!=g1)
y=pre[y];
if(x==y)
{
puts("yes");
continue;
}
if(low[x]<dfn[g1] && low[y]<dfn[g1])
puts("yes");
else
puts("no");
continue;
}
puts("no");
}
}
}
return 0;
}