离线+并查集
title: 离线+并查集
categories:
- ICPC
tags:
- null
abbrlink: e2382ff9
date: 2023-04-02 00:00:00
离线+并查集
LCA&DSU&MST - jzcrq - 博客园 (cnblogs.com)
多次询问两点间的瓶颈路,也就是u到v所有路径中边权的最小值最大。
Sol:考虑先将所有询问离线。考虑建立最大生成树的过程,设联通块s1和s2要被边权为w的边连通。对于存在点u在s1,v在s2的询问的答案就是w。为了保证时间复杂度我们考虑启发式合并,注意判断大小的时候只需要交换u和v本身。把询问的对应点和编号挂在点上,每次把size小的部分的点拿出来更新答案和询问。无法回答的插入新的根中。
void solve() {
int n, m;
cin >> n >> m;
vector<array<int, 3>> edg(m + 1);
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
edg[i] = {w, u, v};
}
int q;
cin >> q;
vector<vector<pii>> qv(n + 1);
for (int i = 1; i <= q; i++) {
int u, v;
cin >> u >> v;
qv[u].push_back({v, i});
qv[v].push_back({u, i});
}
sort(edg.begin() + 1, edg.end(), [](auto i, auto j) {
return i[0] > j[0];
});
DSU dsu(n);
vector<int> ans(q + 1, -1);
deb(edg);
for (int i = 1; i <= n; i++) deb(i, qv[i]);
for (int i = 1; i <= m; i++) {
auto [w, u, v] = edg[i];
deb(w, u, v);
u = dsu.find(u), v = dsu.find(v);
deb(u, v);
if (u == v) {
continue;
} else {
if (qv[v].size() > qv[u].size()) {
swap(u, v);
}
deb(v, qv[v]);
for (auto [nx, id] : qv[v]) {
deb(v, nx, id);
deb(ans[id]);
if (ans[id] > 0)
continue;
if (dsu.find(nx) == u)
ans[id] = w;
else
qv[u].push_back({nx, id});
}
dsu.merge(u, v);
}
}
for (int i = 1; i <= q; i++) cout << ans[i] << endl;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱飞鱼的blog!