NOIP2009 最优贸易

题意

在一张节点带有权值的图上找出一条从 \(1\)\(n\) 的路径,使得路径上两点 \(p,q\) 满足先经过 \(p\) 再经过 \(q\) ,且 \(val[q]-val[p]\) 最大。

Luogu

分析

考虑跑两遍最短路,一遍求出经过每个节点时当前路径上的 \(val_{min}\) ,另一遍反向求出 \(val_{max}\)

于是就可以再建一个反图,两次SPFA,最后枚举每个节点找出 \(max(d[2][i]-d[1][i])\)就完事辣。

但似乎有神仙只有32行代码......

代码

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100003
#define M 500003
#define il inline
#define re register
#define INF 0x3f3f3f3f
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
	T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

struct edge {
	int to, nxt;
} e1[M], e2[M];

int n, m, ans;
int val[N], d[3][N];
int h1[M], h2[M], c1, c2;
bool vis[N];

void insert(int u, int v) {
	e1[++c1].to = v, e1[c1].nxt = h1[u], h1[u] = c1;
	e2[++c2].to = u, e2[c2].nxt = h2[v], h2[v] = c2;
}

void SPFA(int s, int t) {
	memset(vis, 0, sizeof vis);
	queue <int> q;
	if (s == 1) {
		for (int i = 1; i <= n; ++i) d[1][i] = INF;
		d[1][s] = val[s];
		q.push(s); vis[s] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop(); vis[u] = 0;
			for (int i = h1[u]; i; i = e1[i].nxt) {
				int v = e1[i].to;
				if (d[1][v] > min(d[1][u], val[v])) {
					d[1][v] = min(d[1][u], val[v]);
					if (!vis[v]) q.push(v), vis[v] = 1;
				}
			}
		}
	}
	else {
		for (int i = 1; i <= n; ++i) d[2][i] = 0;
		d[2][s] = val[s];
		q.push(s); vis[s] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop(); vis[u] = 0;
			for (int i = h2[u]; i; i = e2[i].nxt) {
				int v = e2[i].to;
				if (d[2][v] < max(d[2][u], val[v])) {
					d[2][v] = max(d[2][u], val[v]);
					if (!vis[v]) q.push(v), vis[v] = 1;
				}
			}
		}
	}
}

int main() {
	int x, y, z;
	read(n), read(m);
	for (int i = 1; i <= n; ++i) read(val[i]);
	for (int i = 1; i <= m; ++i) {
		read(x), read(y), read(z);
		if (z == 1) insert(x, y);
		else insert(x, y), insert(y, x);
	}
	SPFA(1, n), SPFA(n, 1);
	for (int i = 1; i <= n; ++i) ans = max(ans, d[2][i] - d[1][i]);
	printf("%d", ans);
	return 0;
}
posted @ 2019-11-12 22:23  小蒟蒻hlw  阅读(79)  评论(0)    收藏  举报