前言
其实我感觉本题的难点在于分成奇偶两个不同的最短路来计算,图论和最短路其实不难想。
题目大意
题面有点长,还是放一下链接吧。题目传送门
思路
首先看到这题,图论肯定能想到。之后就可以想出一个暴力做法,模拟一遍这个过程,做一次dfs,然后判断。光看到 L L L 的范围就知道肯定不对。之后想了想,这个 L L L 的范围肯定没有什么在线处理 log n \log{n} logn 的算法了,极大可能要做预处理然后 O ( 1 ) \mathcal{O}(1) O(1) 回答。
之后让我们转化一下思路,其实就是问在 a a a 和 1 1 1 之间存不存在一条长度为 L L L 的路径。考虑最短路,如果从 a a a 到 1 1 1 的最短路比 L L L 大,那么肯定从 L L L 开始不需要到。但是可能出现来回来回的情况。
之后再次进行考虑,可以发现,在两条边之间来回走就可以自给自足了,每一次来回增加 1 1 1 的阶段需要走两次,也就是如果这条边的最短路走出来了 3 3 3,那么也一定可以走出 5 , 7 ⋯ 5,7\cdots 5,7⋯但是不可以确定能否走出 6 6 6,但是偶数如果走出来 2 2 2 就一定可以走出 6 6 6,所以要按照奇偶分最短路。之后在根据 L L L 的奇偶对奇偶最短路进行判断即可。
需要注意,如果 1 1 1 是孤立的,则它没有偶数最短路,所以做bfs时先把 1 1 1 的连接边放进队列里即可。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
vector<ll>adj[MAXN];
ll dis[MAXN][3];
ll n,m,Q;
int main(){
scanf("%lld%lld%lld",&n,&m,&Q);
for (int i = 1; i <=m ; ++i) {
ll u,v;
scanf("%lld%lld",&u,&v);
adj[u].push_back(v);
adj[v].push_back(u);
}
memset(dis,0x3f,sizeof(dis));
queue<pair<ll,ll> >q;
for (int i = 0; i <adj[1].size() ; ++i) {
ll v=adj[1][i];
dis[v][1]=1;
q.push({v,1});
}
while (!q.empty()){
ll u=q.front().first,w=q.front().second+1;
q.pop();
for (int i = 0; i <adj[u].size() ; ++i) {
ll v=adj[u][i],type=w%2;
if(w<dis[v][type]){
dis[v][type]=w;
q.push({v,w});
}
}
}
for (int T = 1; T <=Q ; ++T) {
ll a,L;
scanf("%lld%lld",&a,&L);
if(dis[a][L%2]>L){
printf("No\n");
}else{
printf("Yes\n");
}
}
return 0;
}
总结
我们知道了本题可以使用奇偶最短路进行判断,同时可以根据暴力和输入数据的大小去推断可能的算法。在本题中我们通过暴力和 L L L 的范围推断出不太可能有在线的做法。