分类:最短路 【Dijkstra+优先队列版】
传送门:https://www.zhixincode.com/contest/1/problem/F
思路:
/*
初始时,在第一座山上,所以从1->n的过程中经过的山高度不会超过
t=h[0]+k(k为题目给的初始体力值),
比 t 高的山都会贡献(h[i]-t)^2,这个值就加到边权值上面即可
由于每座山的高度只能降低一次,所以建图的时候两个边分开建
由题:n座山,山高度hi,连通山的边权z 均<=100000
我们要加上平方倍的值,应该开longlong才合理
*/
小知识
- 关于pair<first,second> 以first为键值进行排序
- 优先队列 默认排序为降序,所以存距离的时候,存该距离的负数即可
- vector push_back({a,b})写起来方便
AC代码:
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=2e+5;
typedef long long ll;
int n,m,k,s,t;
ll dis[maxn],h[maxn];
int vis[maxn];
vector<pair<int,ll>>E[maxn];//i->int 边权为ll
void init()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++)E[i].clear();
}
void Dijkstra()
{
priority_queue<pair<ll,int>>q;//以距离为排序键值
dis[s]=0;
q.push({-dis[s],s});
while(!q.empty())
{
int now=q.top().second;
q.pop();
if(vis[now])continue;
vis[now]=1;
for(ll j=0;j<E[now].size();j++)
{
int t=E[now][j].first;
if(!vis[t] && dis[t]>dis[now]+E[now][j].second)
{
dis[t]=dis[now]+E[now][j].second;
q.push({-dis[t],t});
}
}
}
}
int main()
{
init();
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>h[i];
k+=h[1];//初始体力,也为最大高度
int a,b;ll z;
while(m--)
{
cin>>a>>b>>z;
if(h[b]>k) E[a].push_back({b,z+(h[b]-k)*(h[b]-k)});
else E[a].push_back({b,z});
if(h[a]>k) E[b].push_back({a,z+(h[a]-k)*(h[a]-k)});
else E[b].push_back({a,z});
}
s=1,t=n;
Dijkstra();
cout<<dis[t]<<endl;
return 0;
}