let menu = ["Home", "Algorithms", "CodeHub", "VNOI Statistics"];
Ta thấy đường đi có thông lượng lớn nhất giữa 2 máy chính là đường đi trên cây khung lớn nhất.
Vì vậy, bài này ta cần tìm cây khung lớn nhất, sau đó với mỗi cạnh
(u,v) không thuộc cây khung, ta tìm trọng số nhỏ nhất trên đường đi
từ u đến v trong cây khung. Để không bị quá thời gian, code hld.cpp
dùng
heavy-light decomposition, còn code tarjan.cpp
dùng Tarjan’s offline LCA (Xem
các tài liệu đính kèm bên trên).
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define LL long long
#define BLACK true
struct edge { int c, u, v; };
bool operator < (const edge &a, const edge &b) {
return a.c > b.c;
}
struct dsu {
int *cha, *rank;
dsu(int n): cha(new int[n+1]) {
for (int i=0; i<=n; i++) cha[i] = i;
}
int find(int u) {
if (cha[u] != u) cha[u] = find(cha[u]);
return cha[u];
}
void join(int u, int v) {
if (rand()&1) swap(u, v);
cha[find(u)] = find(v);
}
};
namespace lca {
LL res = 0;
int n, cha[100001], c[100001];
bool color[100001];
vector<int> queries[100001];
struct pack { int c, v; };
vector<pack> ke[100001];
struct queue_type { int u, v; };
vector<queue_type> queue[100001];
int find(int u) {
if (cha[u] != u) {
int tmp = cha[u];
cha[u] = find(cha[u]);
c[u] = min(c[u], c[tmp]);
}
return cha[u];
}
void dfs(int u, int dad) {
cha[u] = u;
for (pack p: ke[u]) if (p.v != dad) {
dfs(p.v, u);
cha[p.v] = u;
c[p.v] = p.c;
}
color[u] = BLACK;
for (int v: queries[u]) if (color[v] == BLACK) {
queue[find(v)].push_back({u, v});
}
for (auto q: queue[u]) {
find(q.u), find(q.v);
res += min(c[q.u], c[q.v]);
}
}
void solve() {
for (int i=1; i<=n; i++) c[i] = 10000000;
dfs(1, 0);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int n, m; cin >> n >> m;
vector<edge> edges(m);
for (edge &e: edges) cin >> e.u >> e.v >> e.c;
sort(edges.begin(), edges.end());
dsu d(n);
LL res = 0;
for (edge &e: edges) {
if (d.find(e.u) != d.find(e.v)) {
d.join(e.u, e.v);
lca::ke[e.u].push_back({e.c, e.v});
lca::ke[e.v].push_back({e.c, e.u});
} else {
res += e.c;
lca::queries[e.u].push_back(e.v);
lca::queries[e.v].push_back(e.u);
}
}
lca::n = n;
lca::solve();
cout << lca::res - res;
return 0;
}
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
struct pack{ int u, v, c; };
typedef vector<vector<int>> dsk;
struct universe {
vector<int> cha, rank;
universe(int n): cha(n + 1), rank(n + 1, 0) {
for (int i=1; i<=n; i++) cha[i] = i;
}
int find(int u) {
if (cha[u] != u) cha[u] = find(cha[u]);
return cha[u];
}
bool join(int u, int v) {
if (u == v) return false;
if (rank[u] == rank[v]) rank[u]++;
if (rank[u] > rank[v]) cha[v] = u;
else cha[u] = v;
return true;
}
};
inline void minimize(int &x, int y) {
if (x > y) x = y;
}
struct Hld {
dsk ke;
vector<int> nChild, cha, bac, chainHead, chain, pos;
vector<int> f, r, w;
int n;
Hld(int n, dsk &&ke): ke(ke),
nChild(n + 1, 0), cha(n + 1), bac(n + 1),
chainHead(1, 0), chain(n + 1), pos(n + 1),
f(n+1, 1e9), r(n+1, 1e9), w(n+1, 1e9), n(n)
{
prepare(1);
int nChain = 0, count = 0;
hld(1, nChain, count);
}
int prepare(int u) {
nChild[u] = 1;
for (int i=0; i<(int)ke[u].size(); i++) if (nChild[ke[u][i]]) {
ke[u][i] = ke[u].back();
ke[u].pop_back();
break;
}
for (auto v: ke[u]) {
cha[v] = u;
bac[v] = bac[u] + 1;
nChild[u] += prepare(v);
}
return nChild[u];
}
void hld(int u, int &nChain, int &count) {
if (!chainHead[nChain]) chainHead[nChain] = u;
chain[u] = nChain;
pos[u] = ++count;
int con = 0;
for (auto v: ke[u]) if (!con || nChild[con] < nChild[v]) con = v;
if (con) hld(con, nChain, count);
for (auto v: ke[u]) if (v != con) {
nChain++;
chainHead.push_back(0);
hld(v, nChain, count);
}
}
void bitUp(int x, int i) {
r[i] = x;
while(i <= n) minimize(f[i], x), i += i & (-i);
}
int bitGet(int u, int v) {
if (u > v) swap(u, v);
u += 1;
int res = 1e9;
while (u <= v) {
if (u <= (v - v & (-v))) {
minimize(res, f[v]);
v -= v & (-v);
} else {
minimize(res, r[v]);
v -= 1;
}
}
return res;
}
void update(int u, int v, int c) {
if (chain[u] != chain[v]) {
if (cha[u] == v) w[u] = c;
else w[v] = c;
} else {
if (cha[u] == v) bitUp(c, pos[u]);
else bitUp(c, pos[v]);
}
}
int query(int u, int v) {
int res = 1e9;
while (chain[u] != chain[v]) {
int hu = chainHead[chain[u]], hv = chainHead[chain[v]];
if (bac[hu] > bac[hv]) swap(u, v), swap(hu, hv);
minimize(res, bitGet(pos[v], pos[hv]));
minimize(res, w[hv]);
v = cha[hv];
}
minimize(res, bitGet(pos[u], pos[v]));
return res;
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int n, m; cin >> n >> m;
universe s(n);
vector<pack> edges(m);
for (auto &e: edges) cin >> e.u >> e.v >> e.c;
sort(edges.begin(), edges.end(), [](pack &a, pack &b){return a.c > b.c;});
vector<pack> q, tree;
dsk ke(n + 1);
for (auto &e: edges) {
if (s.join(s.find(e.u), s.find(e.v))) {
ke[e.u].push_back(e.v);
ke[e.v].push_back(e.u);
tree.push_back(e);
} else q.push_back(e);
}
Hld hld(n, move(ke));
for (auto &x: tree) hld.update(x.u, x.v, x.c);
LL res = 0;
for (auto &q: q) res += (LL)(hld.query(q.u, q.v) - q.c);
cout << res;
return 0;
}