题目描述
题目分析
- 假设存在一种路径,从
i点出发走
k步走到1号点,那么显然若1号点有出边的话,肯定也存在一种路径,从
i点出发走
k+2步走到1号点。
- 证明:1号点随便选一个出边走出去,再走回来,就可以了(显然)。
- 前提的处理非常简单,直接输出NO即可。但也非常坑人,我在考场的时候就没有想到有这种情况。
- 处理完特殊情况后,我们就可以运用上面的性质了。
- 对于一个点
i,如果
i到1的最短距离为
k,那么距离为
k+2,
k+4......,都将会输出“YES”,对于
k−2,
k−4......,都一定不合法。
- 所以,对于询问中的
L,如果
L和最短路奇偶性相同,只需判断L是否小于最短路即可。
- 假如奇偶性不同呢?
- 自然地,我们可以考虑求一遍另外一种奇偶性的最短路。例如,最短距离
k是偶数,我们可以求另外一个“最短路”
g,且保证
g是一个奇数。
- 这样的最短路怎么求呢?有一个奇技淫巧:把每一个点拆成两个点,一个记录的是奇数的最短路,一个记录的是偶数的最短路。对于原图的一条边
(x,y),我们连两条边:
(x0,y1),(x1,y0)。为什么要这样建图?因为
x的偶数最短路可以更新
y的奇数最短路,反之亦然,所以这样建边就可以同时求出每一个点的偶数最短路与奇数最短路了。
- 问我怎么求最短路?
- 每条边的长度为1,肯定是用宽搜啊!!
(这么想来,好像算法完全没有超纲)
代码
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+100;
struct node{
int x,y,next;
}a[2*N];int len,last[N];
void ins(int x,int y){
a[++len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
bool bk[N][2];int d[2*N][2],f[N][2];
int main()
{
freopen("work.in","r",stdin);
freopen("work.out","w",stdout);
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
len=0;memset(last,0,sizeof(last));
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
int SUM=0;
for(int k=last[1];k;k=a[k].next) SUM++;
if(SUM==0){
for(int i=1;i<=q;i++) printf("No\n");
return 0;
}
memset(f,60,sizeof(f));
int st=0,ed=1;
d[1][0]=1;d[1][1]=0;f[1][0]=0;
memset(bk,true,sizeof(bk));bk[1][0]=false;
while(st<ed){
st++;
int x=d[st][0],c=d[st][1];
for(int k=last[x];k;k=a[k].next){
int y=a[k].y;
if(bk[y][1-c]){
f[y][1-c]=f[x][c]+1;
bk[y][1-c]=false;
d[++ed][0]=y;d[ed][1]=1-c;
}
}
}
for(int i=1;i<=q;i++){
int A,L;bool pd=false;
scanf("%d%d",&A,&L);
if(L%2==0&&f[A][0]<=L) pd=true;
if(L%2==1&&f[A][1]<=L) pd=true;
if(pd) printf("Yes\n");
else printf("No\n");
}
return 0;
}