2026年9月GESP真题及题解(C++八级):末班车

题目描述
城市里有 n n n 个地铁站以及 m m m 条地铁线路,地铁站依次以 1 , 2 , ... , n 1,2,\ldots,n 1,2,...,n 编号。
第 i i i 条地铁线路( 1 ≤ i ≤ m 1\le i\le m 1≤i≤m)的列车从地铁站 u i u_i ui 单向驶向地铁站 v i v_i vi,最晚发车时间为第 l i l_i li 分钟,途中行驶需要 t i t_i ti 分钟。从第 0 0 0 分钟到第 l i l_i li 分钟,每分钟都会有一班列车从地铁站 u i u_i ui 发出。第 x x x 分钟( 0 ≤ x ≤ l i 0\le x\le l_i 0≤x≤li)发出的列车会在第 x + t i x+t_i x+ti 分钟到达地铁站 v i v_i vi,乘坐这班列车的乘客可以换乘第 x + t i x+t_i x+ti 分钟以及之后的所有从地铁站 v i v_i vi 发出的任意线路的列车。
现在有 q q q 组询问。第 i i i 组询问( 1 ≤ i ≤ q 1\le i\le q 1≤i≤q)给出起点地铁站编号 x i x_i xi,终点地铁站编号 y i y_i yi 以及出发时间 s i s_i si,你需要判断第 s i s_i si 分钟从地铁站 x i x_i xi 出发是否能到达地铁站 y i y_i yi。第 s i s_i si 分钟从地铁站 x i x_i xi 出发意味着你可以乘坐第 s i s_i si 分钟以及之后的所有从地铁站 x i x_i xi 发出的任意线路的列车。
输入格式
第一行,三个正整数 n , m , q n,m,q n,m,q,分别表示地铁站数量,地铁线路数量,询问数量。
接下来 m m m 行,每行四个整数 u i , v i , l i , t i u_i,v_i,l_i,t_i ui,vi,li,ti,分别表示地铁线路的起点,终点,最晚发车时间,行驶所需时间。
接下来 q q q 行,每行三个整数 x i , y i , s i x_i,y_i,s_i xi,yi,si,分别表示行程起点,行程终点,出发时间。
输出格式
输出共 q q q 行。对于每组询问,如果第 s i s_i si 分钟从地铁站 x i x_i xi 出发能到达地铁站 y i y_i yi 则输出一行 Yes,否则输出一行 No。请注意输出区分大小写。
输入输出样例 1
输入 1
3 4 5
1 2 3 3
2 3 5 2
3 1 4 1
1 3 0 6
1 3 2
2 1 2
2 1 3
3 2 2
3 2 3
输出 1
Yes
Yes
No
Yes
No
说明/提示
对于 40 % 40\% 40% 的测试点,保证 q ≤ 100 q\le 100 q≤100。
对于所有测试点,保证:
- 1 ≤ n ≤ 500 1\le n\le 500 1≤n≤500
- 1 ≤ m ≤ 1000 1\le m\le 1000 1≤m≤1000
- 1 ≤ q ≤ 5 × 10 5 1\le q\le 5\times 10^5 1≤q≤5×105
- 1 ≤ u i , v i , x i , y i ≤ n 1\le u_i,v_i,x_i,y_i\le n 1≤ui,vi,xi,yi≤n
- 0 ≤ l i , s i ≤ 10 5 0\le l_i,s_i\le 10^5 0≤li,si≤105
- 1 ≤ t i ≤ 10 4 1\le t_i\le 10^4 1≤ti≤104
思路分析
定义 f[y][x] 表示:若终点为 y,从站点 x 出发,最晚可以在第 f[y][x] 分钟出发并到达 y。
如果询问的出发时间 s <= f[y][x],则可以从 x 等到最晚可行发车时间,因此输出 Yes;否则输出 No。
反向递推:
对于一条边 u -> v,最晚发车时间为 l,耗时为 t。
如果从 u 出发想最终到达 y,那么选择第 k 分钟发车时,需要满足:
k <= l- 到达
v的时间是k + t - 从
v还能到达y,所以需要k + t <= f[y][v]
因此:
text
k <= min(l, f[y][v] - t)
所以:
text
f[y][u] = max( min(l, f[y][v] - t) )
特殊地,f[y][y] = +∞,因为已经在终点。
对每个终点 y 反向建图,从 y 开始用大根堆做类似 Dijkstra 的倒推。由于 t >= 1,越往前倒推,最晚出发时间只会变小,因此当前堆中最大的未确定值就是最终值。
时间复杂度:
O ( n ∗ ( n + m ) l o g n + q ) O(n * (n + m) log n + q) O(n∗(n+m)logn+q)
空间复杂度:
O ( n 2 + m ) O(n^2+m) O(n2+m)
代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
const int N=505;//最大站点数加5
const int I=1e9;//无穷大,表示终点本身
struct E{int u,l,t;};//反向边:u为起点,l为最晚发车,t为耗时
int f[N][N];//f[y][x]表示终点y,起点x的最晚出发时间
vector<E> g[N];//g[v]存所有指向v的边
int main(){
ios::sync_with_stdio(false);//关闭同步
cin.tie(0);//解绑输入
cout.tie(0);//解绑输出
int n,m,q;//站点数,线路数,询问数
cin>>n>>m>>q;//读入规模
for(int i=0;i<m;i++){//读入每条线路
int u,v,l,t;//起点,终点,最晚发车,耗时
cin>>u>>v>>l>>t;//读入线路
g[v].push_back({u,l,t});//反向存储,便于从终点倒推
}
for(int y=1;y<=n;y++){//枚举每个终点y
int d[N];//d[u]表示从u到y的最晚出发时间
for(int i=1;i<=n;i++) d[i]=-1;//初始不可达
priority_queue<pair<int,int>> p;//大根堆,按最晚时间从大到小
d[y]=I;//终点本身随时都在
p.push({I,y});//从终点开始倒推
while(!p.empty()){//类似Dijkstra
int w=p.top().first;//当前最晚时间
int v=p.top().second;//当前站点
p.pop();//弹出
if(w!=d[v]) continue;//过期状态
for(int i=0;i<(int)g[v].size();i++){//遍历所有指向v的边
int u=g[v][i].u;//边的起点
int l=g[v][i].l;//边最晚发车
int t=g[v][i].t;//边耗时
int c=min(l,w-t);//从u最晚发车时间
if(c>=0&&c>d[u]){//能更新且非负
d[u]=c;//更新
p.push({c,u});//入堆
}
}
}
for(int x=1;x<=n;x++) f[y][x]=d[x];//保存答案
}
while(q--){//处理询问
int x,y,s;//起点,终点,出发时间
cin>>x>>y>>s;//读入询问
if(s<=f[y][x]) cout<<"Yes\n";//不晚于最晚出发时间
else cout<<"No\n";//否则不能
}
return 0;
}
功能分析
该程序预处理每个终点 y 到所有起点 x 的最晚可行出发时间 f[y][x]。
对于每次询问 (x, y, s),只需要判断 s <= f[y][x] 是否成立。
成立说明可以从 x 在第 s 分钟或之后出发并最终到达 y,输出 Yes;否则输出 No。
该做法能处理 q 高达 5 × 10 5 5×10^5 5×105 的询问,因为询问部分是 O(1) 的。
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
信奥赛C++普及组CSP-J一等奖通关刷题题单及题解:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}
