qoj18240.Extra Transition

给定无向图与 \(S,T\),其中点带点权 \(w\),判定其是否满足以下条件。

  • 对任意 \(x\),存在形如 \(S\to x\to T\) 的路径。
  • 对任意 \(x,y\),形如 \(S\to x\to y\to T\)\(S\to y\to x\to T\)点不相交路径不同时存在。

若满足以上条件,还需对满足以下条件的 \((x,y)\) 对,计数 \(\sum w_x\times w_y\)

  • \(x<y\),原图中不存在边 \((x,y)\),且加入边 \((x,y)\) 后仍然满足上述条件。

\[n\le 2\times 10^5 \]


首先我们需要敏锐的注意到,图满足上述条件当且仅当其为一个 二端串并联图

换句话说其能在仅使用 缩二度点叠合重边 操作下被缩为仅包含 \((S,T)\) 的图。

证明参考官方题解()一句话总结就是合法等价于不出现下面这个形式,而这等价于二端串并联图。

alt text

在此基础上考虑什么样的边可以加入。

alt text

如图,考虑一个 叠合重边 操作(红色和绿色边)中的点 \(x\),其已经被缩入红色边中。

此时其与一个外部点 \(a\) 间的边 \((a,x)\) 必会形成上上图的结构,即不合法。

除此之外的其他边都合法,不难在串并联图缩边过程中维护。


#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>


inline void solve() {
  typedef long long i64;
  std::unordered_map<i64, int> map;

  i64 n, m;
  std::cin >> n >> m;

  std::vector<i64> w(n+1);
  for(int i = 1; i <= n; ++i) std::cin >> w[i];

  i64 ans = 0;
  std::vector<int> deg(n+1);
  std::vector<std::basic_string<int>> g(n+1);
  for(int x, y; m--; ) {
    std::cin >> x >> y;
    if(x > y) std::swap(x, y);
    map[x*n+y] = 0;
    ++deg[x], ++deg[y];
    g[x] += y, g[y] += x;
    ans -= w[x] * w[y];
  }

  int S = 1, T = n; std::queue<int> q;
  for(int i = 1; i <= n; ++i) if(deg[i] == 2) q.push(i);

  int cnt = 0;
  std::vector<bool> vis(n+1);

  auto wi = [&](int x, int y) {
    if(x > y) std::swap(x, y);
    return map.find(x*n+y);
  };
  
  while(!q.empty()) {
    int u = q.front(); q.pop();
    if(u == S || u == T) continue;
    if(deg[u] < 2) break;
    ++cnt, vis[u] = 1;
    int x = 0, y = 0;
    for(auto& v: g[u]) if(!vis[v]) y = x, x = v;
    auto _a = wi(x, u), _b = wi(y, u);
    int a = _a -> second, b = _b -> second;
    map.erase(_a), map.erase(_b);
    ans += 1ll * w[x] * (w[u] + b) + 1ll * w[y] * (w[u] + a) + 1ll * a * b;
    int c = a + b + w[u];
    auto p = wi(x, y);
    if(p != map.end()) {
      p -> second = 0;
      if(--deg[x] == 2) q.push(x);
      if(--deg[y] == 2) q.push(y);
    } else {
      g[x] += y, g[y] += x;
      if(x > y) std::swap(x, y);
      map.insert({x*n+y, c});
    }
  }
  ans += w[S] * w[T];
  if(cnt == n - 2) 
    std::cout << ans << "\n";
  else std::cout << "bad\n";
}

int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cin.tie(0);
  int t; std::cin >> t; while(t--) solve();
}
posted @ 2026-08-22 04:24  CuteNess  阅读(14)  评论(0)    收藏  举报