CH-6101 (SPFA维护路径信息)


解法参考进阶指南

题意:找一条1到n的路径使得路径上选2个点使得之前经过的那个点的权值减之后经过的那个点的权值的值最大。

可以用SPFA维护(维护方法与POJ-3662相似)点1到点\(i\)的路径上所有点的最小值\(D[i]\),再维护一个\(i\)\(n\)的最大值\(F[i]\)(等价于建个反图维护\(n\)\(i\)的最大值),枚举每个点\(F[i]-D[i]\),取个最大值就是答案。

const int maxn = 1e5+10;
int val[maxn], F[maxn], D[maxn];
bool inq[maxn];
int n, m;

vector e[maxn], e2[maxn];

void spfa1(int s) {
  mem(D,0x3f);
  mem(inq,0);
  queue q;
  q.push(s);
  inq[s] = 1;
  D[s] = val[s];
  while (!q.empty()) {
    int u = q.front(); q.pop();
    inq[u] = 0;
    for (auto v : e[u]) {
      if (D[v] > min(D[u], val[v])) {
        D[v] = min(D[u],val[v]);
        if (!inq[v]) q.push(v), inq[v] = 1;
      }
    }
  }
}

void spfa2(int s) {
  mem(F,0);
  mem(inq,0);
  queue q;
  q.push(s);
  inq[s] = 1;
  F[s] = val[s];
  while (!q.empty()) {
    int u = q.front(); q.pop();
    inq[u] = 0;
    for (auto v : e2[u]) {
      if (F[v] < max(F[u], val[v])) {
        F[v] = max(F[u], val[v]);
        if (!inq[v]) q.push(v), inq[v] = 1;
      }
    } 
  }
}

void run() {
  n = rd(), m = rd();
  rep(i,1,n) {
    val[i] = rd();
  }
  while (m--) {
    int u = rd(), v = rd(), op = rd();
    e[u].pb(v), e2[v].pb(u);
    if (op==2) e[v].pb(u), e2[u].pb(v);
  }
  spfa1(1);
  spfa2(n);
  int ans = 0;
  rep(i,1,n) ans = max(ans, F[i]-D[i]);
  pnt(ans);
}