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

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

如图,考虑一个 叠合重边 操作(红色和绿色边)中的点 \(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();
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/22625290

浙公网安备 33010602011771号