E - Skiing
题意:
给定
n
n
n 点高度为
a
i
a_i
ai,初始位置为
1
1
1,求从
1
1
1 出发的最长路(经过边权的代数和最大)是多少
两个点之间的边权这样定义:
现在从
x
x
x 要去
y
y
y
如果
a
x
>
=
a
y
a_x>=a_y
ax>=ay,那么边权为
a
x
−
a
y
a_x-a_y
ax−ay
如果
a
x
<
a
y
a_x<a_y
ax<ay,那么边权为
2
∗
(
a
x
−
a
y
)
2*(a_x-a_y)
2∗(ax−ay)
思路:
虽然是让求最长路,但是给定图是无向图,我们无法用拓扑排序
本题路径权值和势能有关,因为势能差是一定的,可以转化为最短路问题
设终点的高度为
k
<
a
1
k < a_1
k<a1
那么途中经过的正边权和为
a
1
−
k
a_1-k
a1−k,最后的答案至多为这个
由于可能经过负边权,这会使得最后的答案更小
如果终点固定,那么我们需要最小化其中经过的负边权,这样才能最后剩余最多
然后考虑建这样一个图
下坡路边权设为
0
0
0,上坡路设为
a
[
t
o
]
−
a
[
n
o
w
]
(
上
去
再
下
来
的
时
候
支
出
大
于
获
得
,
无
法
弥
补
的
消
耗
)
a[to]-a[now](上去再下来的时候支出大于获得,无法弥补的消耗)
a[to]−a[now](上去再下来的时候支出大于获得,无法弥补的消耗)
那么从
1
1
1 到
i
i
i 的正边权
a
1
a_1
a1–>
a
i
a_i
ai 是固定,我们需要最小化路程
可以发现问题就转化为了求起点为
1
1
1 的单源最短路
枚举终点维护最大值即可
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int a[maxn];
vector <int> e[maxn];
ll dis[maxn];
bool vis[maxn];
void dij(){
priority_queue <pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > q;
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0;
q.push({0, 1});
while(!q.empty()){
int now = q.top().second;q.pop();
if(vis[now]) continue;
vis[now] = 1;
for(auto to : e[now]){
ll d = max(0, a[to] - a[now]);
if(dis[to] > dis[now] + d){
dis[to] = dis[now] + d;
q.push({dis[to], to});
}
}
}
}
void work()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i) cin >> a[i];
for(int i = 1; i <= m; ++i){
int x, y;cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
dij();
ll ans = 0;
for(int i = 1; i <= n; ++i)
ans = max(ans, a[1] - a[i] - dis[i]);
cout << ans;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}
1万+

被折叠的 条评论
为什么被折叠?



