描述

C国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为1条。
C国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙来到C国旅游。当他得知“同一种商品在不同城市的价格可能会不同”这一信息之后,便决定在旅游的同时,利用商品在不同城市中的差价赚一点旅费。设C国 n 个城市的标号从 1~n,阿龙决定从1号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的过程中,任何城市可以被重复经过多次,但不要求经过所有 n 个城市。
阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另一个城市卖出这个水晶球,用赚取的差价当做旅费。因为阿龙主要是来C国旅游,他决定这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。
现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。

输入格式

   第一行包含 2 个正整数n 和m,中间用一个空格隔开,分别表示城市的数目和道路的
数目。
   第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这n 个城
市的商品价格。
   接下来 m 行,每行有3 个正整数,x,y,z,每两个整数之间用一个空格隔开。如果z=1,表示这条道路是城市x 到城市y 之间的单向道路;如果z=2,表示这条道路为城市x 和城市y 之间的双向道路

输出格式

一个整数,表示答案。

样例输入

5 5
4 3 5 6 1
1 2 1
1 4 1
2 3 2
3 5 1
4 5 2

样例输出

5

数据范围与约定

  • 输入数据保证 1 号城市可以到达n 号城市。
    对于 10%的数据,1≤n≤6。
    对于 30%的数据,1≤n≤100。
    对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。
    对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市
    水晶球价格≤100。

测试地址:CH6101


如果题意莫名其妙,那么莫名其妙的不是出题人的脑袋就是我们的脑袋。——zrt

个人思路:

  • 注意到进行最多一次最多能赚取和输入格式,可以考虑一下单源最短路径。
  • 假设我们是阿龙 的话,当然会在路径上选择最便宜的地方买物品,最贵的地方售出物品。
  • 如果对Dijkstra的更新方式进行修改,就可以求出从源点到每一个点购入的最便宜价格。(对Dijkstra的理解)
  • 形象地说,我们如果是阿龙的话,等于尝试走到每个点,并看从源点到每个点时,能购入的最便宜价格。
  • 到这里,就有一个小技巧了。既然求得购入价格可以正着走,那么是否求售出价格可以反着走呢?
  • 答案是可以的。
  • 最终,进行两次Dijkstra,再枚举ans=max(售出价格[i]-购入价格[i])即可求出答案。注意,第二次Dijkstra要求进行在反图上。

#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
int n;
struct Edge_Low{
	int from,to,nxt;
}e_Low[MAXM];
int head_Low[MAXN],edgeCnt_Low=0;
void addEdge_Low(int u,int v){
	e_Low[++edgeCnt_Low].from=u;
	e_Low[edgeCnt_Low].to=v;
	e_Low[edgeCnt_Low].nxt=head_Low[u];
	head_Low[u]=edgeCnt_Low;
}
int price[MAXN];//各个点的价格 
const int INF=2100000000;
struct Node{
	int nowPoint,nowValue;
	bool operator <(const Node &a)const{
		return a.nowValue<nowValue;
	}
};
int s_Low;
int dis_Low[MAXN];
void dijkstra_Low(){//收购尽量低价 
	for(int i=1;i<=n;i++)dis_Low[i]=INF;
	priority_queue<Node> q;
	q.push(Node{s_Low,price[s_Low]});dis_Low[s_Low]=price[s_Low];
	while(!q.empty()){
		Node nowNode=q.top();q.pop();
		int nowPoint=nowNode.nowPoint,nowValue=nowNode.nowValue;
		if(dis_Low[nowPoint]!=nowValue)continue;
		for(int i=head_Low[nowPoint];i;i=e_Low[i].nxt){
			int nowV=e_Low[i].to;
			if(dis_Low[nowV]>dis_Low[nowPoint]){
				dis_Low[nowV]=min(dis_Low[nowPoint],price[nowV]);
				q.push(Node{nowV,dis_Low[nowV]});
			}
		}
	}
}
struct Edge_High{
	int from,to,nxt;
}e_High[MAXM];
int head_High[MAXN],edgeCnt_High=0;
void addEdge_High(int u,int v){
	e_High[++edgeCnt_High].from=u;
	e_High[edgeCnt_High].to=v;
	e_High[edgeCnt_High].nxt=head_High[u];
	head_High[u]=edgeCnt_High;
}
int s_High;
int dis_High[MAXN];
void dijkstra_High(){//售出尽量高价 
	for(int i=1;i<=n;i++)dis_High[i]=-INF;
	priority_queue<Node> q;
	q.push(Node{s_High,price[s_High]});dis_High[s_High]=price[s_High];
	while(!q.empty()){
		Node nowNode=q.top();q.pop();
		int nowPoint=nowNode.nowPoint,nowValue=nowNode.nowValue;
		if(dis_High[nowPoint]!=nowValue)continue;
		for(int i=head_High[nowPoint];i;i=e_High[i].nxt){
			int nowV=e_High[i].to;
			if(dis_High[nowV]<dis_High[nowPoint]){
				dis_High[nowV]=max(dis_High[nowPoint],price[nowV]);
				q.push(Node{nowV,dis_High[nowV]});
			}
		}
	}
}
int main(){
	int m;
	scanf("%d%d",&n,&m);
	s_Low=1,s_High=n;
	for(int i=1;i<=n;i++)scanf("%d",&price[i]);
	for(int i=1;i<=m;i++){
		int u,v,z;
		scanf("%d%d%d",&u,&v,&z);
		addEdge_Low(u,v);
		addEdge_High(v,u);
		if(z==2){
			addEdge_Low(v,u);
			addEdge_High(u,v);
		}
	}
	dijkstra_Low();
	dijkstra_High();
	int ans=-INF;
	for(int i=1;i<=n;i++)ans=max(ans,dis_High[i]-dis_Low[i]);
	printf("%d\n",ans);
	return 0;
}