題目描述
題目分析
- 假設存在一種路徑,從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;
}