洛谷P1073 最优贸易
\(\Large\textbf{Solution: } \large{1.分层图\\首先如果开两层,第一层到第二层表示买,第二层到第一层表示卖,会出现环或者卖卖多次的情况。\\所以开三层图,第一层表示没有买,二表示买,三表示卖。然后在图上跑最长路即可。注意到边权为负,所以要写Spfa。\\2.缩点+DP\\首先把图中的环缩成一个点,维护每个环的最大值与最小值,然后拓扑排序即可。我感觉这种做法细节较多,不太好写。}\)
\(\Large\textbf{Code: }\)
#include <bits/stdc++.h>
#define gc() getchar()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 1e5 + 5;
const int M = 5e5 + 5;
const int inf = 0x7fffffff;
int n, m, cnt, head[N * 3 + 100], a[N], vis[N * 3 + 100], dis[N * 3 + 100];
struct Edge {
int to, next, val;
}e[M * 10];
queue<int> q;
inline int read() {
int x = 0;
char ch = gc();
while (!isdigit(ch)) ch = gc();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
return x;
}
inline void add(int x, int y, int w) {
e[++cnt].to = y;
e[cnt].val = w;
e[cnt].next = head[x];
head[x] = cnt;
}
inline void Spfa() {
rep(i, 1, n * 3) dis[i] = -inf;
dis[1] = 0; q.push(1); vis[1] = 1;
while (!q.empty()) {
int cur = q.front(); q.pop();
vis[cur] = 0;
for (int i = head[cur]; i ; i = e[i].next) {
int u = e[i].to;
if (dis[u] < dis[cur] + e[i].val) {
dis[u] = dis[cur] + e[i].val;
if (!vis[u]) q.push(u), vis[u] = 1;
}
}
}
}
int main() {
n = read(), m = read();
rep(i, 1, n) a[i] = read();
int x, y, ju;
while (m--) {
x = read(), y = read(), ju = read();
add(x, y, 0); add(x + n, y + n, 0); add(x + 2 * n, y + 2 * n, 0); add(x, y + n, -a[x]); add(x + n, y + 2 * n, a[x]);
if (ju == 2) {
add(y, x, 0);
add(y + n, x + n, 0);
add(y, x + n, -a[y]);
add(y + n, x + 2 * n, a[y]);
add(y + 2 * n, x + 2 * n, 0);
}
}
Spfa();
printf("%d\n", max(dis[n], dis[3 * n]));
return 0;
}
\(\Large\textbf{Code: }\)
#include <bits/stdc++.h>
#define gc() getchar()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 1e5 + 5;
const int M = 5e5 + 5;
const int inf = 0x7fffffff;
int n, m, cnt, id, top, vis[N], head[N], s[N], a[N], dfn[N], low[N];
int tot, cot, ans[N], in[N], Min[N], bel[N], h[N], Max[N];
struct Edge {
int to, next, fr;
}e[M];
struct EDGE {
int to, next;
}E[M << 1];
inline int read() {
int x = 0;
char ch = gc();
while (!isdigit(ch)) ch = gc();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
return x;
}
inline void add(int x, int y) {
e[++cnt].fr = x;
e[cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
inline void Tarjan(int x) {
low[x] = dfn[x] = ++id;
s[++top] = x; vis[x] = 1;
for (int i = head[x]; i ; i = e[i].next) {
int u = e[i].to;
if (!dfn[u]) Tarjan(u), low[x] = min(low[x], low[u]);
else if (vis[u]) low[x] = min(low[x], dfn[u]);
}
if (dfn[x] == low[x]) {
int y; ++tot;
while (top) {
y = s[top--];
vis[y] = 0;
bel[y] = tot;
Max[tot] = max(Max[tot], a[y]);
Min[tot] = min(Min[tot], a[y]);
if (x == y) break;
}
}
}
inline void Add(int x, int y) {
E[++cot].to = y;
E[cot].next = h[x];
h[x] = cot;
}
inline void DP() {
queue<int> q;
q.push(bel[1]);
ans[bel[1]] = max(ans[bel[1]], Max[bel[1]] - Min[bel[1]]);
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x]; i ; i = E[i].next) {
int u = E[i].to;
--in[u];
Min[u] = min(Min[u], Min[x]);
ans[u] = max(ans[u], max(ans[x], Max[u] - Min[u]));
if (!in[u]) q.push(u);
}
}
}
int main() {
n = read(), m = read();
rep(i, 1, n) a[i] = read();
int x, y, ju;
while (m--) {
x = read(), y = read(), ju = read();
add(x, y);
if (ju == 2) add(y, x);
}
rep(i, 1, n) Min[i] = inf;
rep(i, 1, n) if (!dfn[i]) Tarjan(i);
rep(i, 1, cnt) {
int u = bel[e[i].fr], v = bel[e[i].to];
if (u != v) Add(u, v), ++in[v];
}
DP();
printf("%d\n", ans[bel[n]]);
return 0;
}