题解 P1073 【最优贸易】
stevenzheng2002 · · 题解
某些时候还是要相信自己。
这题明显(对于我来说),一看就是tarjan缩点,至于后面怎么处理还没想好,于是我就写了。写完缩点后,发现有一丝迷茫,后面貌似不太好处理,然后看了看讨论,发现都是什么dfs,两遍SPFA。然后发现貌似没有tarjan缩点的做法,于是乎我开始想这道题怎么用SPFA做,可是呢,我就是放不下原来的做法,于是想了想,发现需要topo_sort一下,然后DP即可,然后就没有然后了。可见一定要相信自己!
分析:
这道题因为有的点它能(被)经过好几次,所以我们可以很容易想到:同一个强连通分量里的点可以互相到达,换言之,就是能来回走无数次。那么我们就可以用tarjan缩点,然后重新建图,对于每个新的图中的点,我们可以维护一下它的
这道题的DP就比较简单了,
然后这道题就结束了,是不是特别弱智。。。
代码:
#include <bits/stdc++.h>
#define REP(i, n) for(int i = 1; i <= n; i ++)
#define REPG(i, x) for(int i = head[x]; i; i = g[i].nxt)
#define mem(x, y) memset(x, y, sizeof(x));
using namespace std;
typedef long long LL;
typedef double DB;
LL Max(LL a, LL b){return a > b ? a : b;}
LL Min(LL a, LL b){return a < b ? a : b;}
const int MAXN = 1e5 + 15;
const int MAXM = 1e6 + 15;
struct Edge{int to, nxt;}g[MAXM], e[MAXN];
int head[MAXN], cnt = 0, w[MAXN], dfn[MAXN], low[MAXN], sta[MAXN], tot = 0, tmp = 0, st, en, hh[MAXN], orzcfz = 0;
int head_sd[MAXN], cnt_sd = 0, w_sd_max[MAXN], w_sd_min[MAXN], belong[MAXN], n, m, ans = 0, in[MAXN];
int maxco[MAXN], minco[MAXN], f[MAXN], mm[MAXN], cnt_cfz = 0;
bool instack[MAXN];
queue <int> q;
void add(int u, int v){g[++ cnt] = (Edge){v, head[u]}; head[u] = cnt;}
void add_sd(int u, int v){e[++ cnt_sd] = (Edge){v, head_sd[u]}; head_sd[u] = cnt_sd;}
void add_edge(int u, int v){add(u, v); add(v, u);}
inline int read(){
int r = 0, z = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') z = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){r = r * 10 + ch - '0'; ch = getchar();}
return r * z;
}
void fre(){
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
}
void tarjan(int u){
dfn[u] = low[u] = ++ tmp; sta[++ tot] = u; instack[u] = 1;
for(int i = head[u]; i; i = g[i].nxt){
int v = g[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]){
ans ++;
while(sta[tot] != u){
int gg = sta[tot]; tot --;
instack[gg] = 0; belong[gg] = ans;
}
tot --; instack[u] = 0; belong[u] = ans;
}
}
void DP(){
memset(minco, 0x3f, sizeof(minco));
minco[hh[1]] = w_sd_min[hh[1]];
for(int i = 1; i <= n; i ++){
int x = hh[i];
for(int j = head_sd[x]; j; j = e[j].nxt){
int y = e[j].to;
minco[y] = min(minco[y], min(minco[x], w_sd_min[x]));
f[y] = max(f[y], max(f[x], max(mm[y], w_sd_max[y] - minco[y])));
}
}
printf("%d\n", f[en]);
}
void topo(){
for(int i = 1; i <= ans; i ++) if(!in[i]){q.push(i); hh[++ cnt_cfz] = i;}
while(!q.empty()){
int u = q.front(); q.pop(); hh[++ orzcfz] = u;
for(int i = head_sd[u]; i; i = e[i].nxt){
int v = e[i].to;
in[v] --;
if(!in[v]) q.push(v);
}
}
DP();
}
void suodian(){
for(int i = 1; i <= n; i ++) if(!belong[i]) belong[i] = ++ ans;
for(int i = 1; i <= n; i ++){
int u1 = belong[i];
for(int j = head[i]; j; j = g[j].nxt){
int v1 = belong[g[j].to];
if(u1 != v1){add_sd(u1, v1); in[v1] ++;}
}
}
for(int i = 1; i <= n; i ++){
w_sd_max[belong[i]] = max(w_sd_max[belong[i]], w[i]);
w_sd_min[belong[i]] = min(w_sd_min[belong[i]], w[i]);
}
for(int i = 1; i <= ans; i ++) mm[i] = w_sd_max[i] - w_sd_min[i];
st = belong[1], en = belong[n];
topo();
}
void solve(){
for(int i = 1; i <= n; i ++){
if(!dfn[i]) tarjan(i);
}
suodian();
}
void init(){
n = read(), m = read();
memset(w_sd_min, 0x3f, sizeof(w_sd_min));
for(int i = 1; i <= n; i ++) w[i] = read();
for(int i = 1; i <= m; i ++){
int u = read(), v = read(), z = read();
if(z == 1) add(u, v);
else add_edge(u, v);
}
solve();
}
int main(){
//fre();
init();
return 0;
}