题解:P11535 [NOISG 2023 Finals] Airplane
看前面两篇题解有些地方没有说清楚,来发一篇解释一下这个思路的可行性。
题意
有一个
思路
观察题目,我们可以发现每一分钟可以改变
但是,这个结论显然没有达到我们的要求。因为一条路径要求到终点时高度为零,因此我们不可能一直上升。但是也不难得出,在路径经过最高点后,我们就不再上升了。
举个栗子
绿色这一段一直上升,而蓝色一段则需要一直下降,交汇的地方就是最高点,那么最高点高度
怎么来的呢?绿色这一段的时间等于
但我们肯定不可能去求一个路径的最高点,于是,我们发现,我们可以通过到达某个点的时间来设定这个路径的最高点,前面我们得到时间可以等于高度,那么我们对于任意一点
解释一下
不难看出,由于两条路径的时间差,我们到达
这个思路还有没有缺陷呢?当然有了。
比如这个
诶我们发现你头顶怎么尖尖的,当这条路径的长度(不是耗时),为奇数时,会出现这么个“尖顶”——(就是一段上升和一段竖直下降),这玩意的耗时为
完结散花。
Code:
#include<bits/stdc++.h>
const int N = 200005, M = 400005 * 2;
using namespace std;
int in(){
int ans = 0, f = 1;
char c = getchar();
while(c < '0' || '9' < c){
if(c == '-')f = -1;
c = getchar();
}
do{
ans = (ans << 3) + (ans << 1) + c - '0';
c = getchar();
}while('0' <= c && c <= '9');
return ans * f;
}
struct node{
int next, to;
}road[M];
int head[N], cnt;
void add(int x, int y){
road[++cnt].next = head[x];
road[cnt].to = y;
head[x] = cnt;
}
int d1[N], d2[N], a[N];
bool vis[N];
int n, m, u, v;
void spfa(int u, int f[]){
memset(vis, 0, sizeof(vis));
f[u] = 0;
queue<int>q;
q.push(u);
while(!q.empty()){
int h = q.front();
q.pop();
for(int i = head[h];i;i = road[i].next){
int r = road[i].to, ext = max(a[r] - f[h] - 1, 0);
if(f[r] > f[h] + ext + 1){
f[r] = f[h] + ext + 1;
if(!vis[r]){
q.push(r);
vis[r] = 1;
}
}
}
vis[h] = 0;
}
}
signed main(){
n = in(), m = in();
for(int i = 1;i <= n;i++)a[i] = in();
for(int i = 1;i <= m;i++){
u = in(), v = in();
add(u, v), add(v, u);
}
memset(d2, 63, sizeof(d2));
memset(d1, 63, sizeof(d1));
spfa(1, d1);
spfa(n, d2);
int ans = INT_MAX;
for(int i = 1;i <= n;i++){
ans = min(max(d1[i] , d2[i]) * 2, ans);
for(int j = head[i];j;j = road[j].next){
int r = road[j].to;
ans = min(max(d1[i], d2[r]) * 2 + 1, ans);
}
}
cout<<ans;
}