Luogu P5663 CSP-J2019 加工零件 题解 [ 绿 ] [ 分层图最短路 ]
加工零件:非常好的一道图论题。CCF 普及组的题目大概也只有图论出的比较巧妙了。
题意简述:给你一张无向图,\(q\) 次询问,判断是否存在一条从 \(a\) 到 \(1\) 且长度为 \(L\) 的路径。
看到 \(L\) 很大,我们立刻想到了要撇开 \(L\) 的限制思考问题。
首先,对于一条路径,我们肯定能找到从 \(1\) 到 \(v\) 的一条最短路径,它的长度为 \(s\)。
此时我们可以发现,这时候我们一定可以找到长度为 \(s,s+2,s+4,...,s+2k\) 的路径。
为什么?因为这张图是无向图,我们可以沿着一条边走,来回一趟,这样我们的时间就会增加 \(2\) 了。
那么假设我们要 \(s+1,s+3,...,s+2k+1\) 的长度怎么办?我们只需要找到一个长度为 \(s+2k+1\) 的最短路径即可,这样长度为 \(s+2k+1+2j\) 的路径就都能找到。
这就启发我们把一个点分为此时时间为奇数和此时时间为偶数两种了。
我们可以把点翻倍,然后 BFS 的过程中记录此时是奇数路径还是偶数路径,进入到相应状态的点中,每个点的每个状态最多只会走到一次,这样就能在 \(O(n)\) 内求解了。这便是同于最短路的一个简单应用。
那么每次询问怎么处理?显然,当 \(L\) 为奇数时,判断它是否大于等于奇数状态的这个点的最短路长度。若是,则说明可以,否则说明到不了。因为他们是同余的。偶数同理。
写代码的时候把 bitset 两维弄反了,喜提 RE,竟然还把样例过掉了,离谱 CCF。
注意 bitset 尖括号里的那一维是最后一维!!!进食厚仁!!!
代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
int n,m,t,dis[1000005][2];
vector<int>g[1000005];
struct node{
int u,s,d;
};
queue<node>q;
bitset<2>vis[1000005];
void init()
{
memset(dis,0x3f,sizeof(dis));
dis[1][0]=0;
vis[1][0]=1;
q.push({1,0,0});
while(!q.empty())
{
node tmp=q.front();
int u=tmp.u,s=tmp.s,d=tmp.d,ns=(s+1)%2;
q.pop();
for(auto v:g[u])
{
if(vis[v][ns]==0)
{
vis[v][ns]=1;
dis[v][ns]=d+1;
q.push({v,ns,d+1});
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>t;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
init();
while(t--)
{
int a,l;
cin>>a>>l;
if(l%2==1)
{
if(dis[a][1]<=l)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else
{
if(dis[a][0]<=l)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}