g 八分钱
一生有爱何惧风飞沙,gp_hash_table 八分钱小练干哈嘛。
只有小于等于阈值的边可以经过所以考虑 Kruskal 做最小瓶颈。
对边权排序之后从小到大枚举左图的最大阈值,用双指针维护右图阈值最小值。只需要支持 check 左右阈值是否合法。
合法的点对个数等于两边各自能通过的点对个数减去两边都能通过的点对个数。前者可以直接做 Kruskal 的时候用并查集简单预处理,后者考虑对每个点记录信息
复杂度
#include <bits/stdc++.h>
#define LL long long
#define ull unsigned long long
#define uint unsigned int
using namespace std;
const int N = 2e5 + 10;
int n, m1, m2; LL K, Ans;
struct Edge { int u, v; LL w; } e1[N], e2[N]; LL res1[N], res2[N];
int fa[N], sz[N];
int Find(int u) { return (u == fa[u] ? u : fa[u] = Find(fa[u])); }
int trans(Edge* e, LL* res, int m) {
for (int i = 1; i <= n; i ++) fa[i] = i, sz[i] = 1;
sort(e + 1, e + 1 + m, [](Edge a, Edge b) { return a.w < b.w; });
int cnt = 0;
for (int i = 1; i <= m; i ++) {
int u = Find(e[i].u), v = Find(e[i].v);
if (u == v) continue;
fa[u] = v; res[cnt + 1] = res[cnt] + 1ll * sz[v] * sz[u];
sz[v] += sz[u]; e[++ cnt] = e[i];
}
return cnt;
}
vector<int> vec[N], cur[N]; int col[N]; int bel[N];
pair<int, int> info[N];
unordered_map<LL, int> hsh; LL curres;
LL get(pair<int, int> a) { return 1ll * a.first * 1145141919 + a.second; }
void undo(int u) {
for (int x : vec[u]) {
curres -= (-- hsh[get(info[x])]);
info[x].first = col[u];
curres += (hsh[get(info[x])] ++);
}
}
int main() {
freopen(".in", "r", stdin); freopen(".out", "w", stdout);
ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n >> m1 >> m2 >> K; Ans = 1e18;
for (int i = 1, u, v, w; i <= m1; i ++) cin >> u >> v >> w, e1[i] = {u, v, w};
for (int i = 1, u, v, w; i <= m2; i ++) cin >> u >> v >> w, e2[i] = {u, v, w};
m1 = trans(e1, res1, m1);
m2 = trans(e2, res2, m2);
for (int i = 1; i <= n; i ++) bel[i] = i, cur[i].push_back(i);
for (int i = 1; i <= m1; i ++) {
int u = bel[e1[i].u], v = bel[e1[i].v];
if (cur[u].size() < cur[v].size()) swap(u, v);
col[i] = v;
for (int x : cur[v]) vec[i].push_back(x), bel[x] = u, cur[u].push_back(x);
}
for (int i = 1; i <= n; i ++) info[i] = {bel[i], i}, hsh[get(info[i])] ++;
for (int i = 1; i <= m1; i ++) if (res1[i] >= K) Ans = min(Ans, e1[i].w);
for (int i = 1; i <= m2; i ++) if (res2[i] >= K) Ans = min(Ans, e2[i].w);
if (!K) { cout << "0\n"; return 0; }
for (int i = 1; i <= n; i ++) cur[i].clear(), cur[i].push_back(i), bel[i] = i;
for (int i = 1, j = m1; i <= m2; i ++) if (j) {
int u = bel[e2[i].u], v = bel[e2[i].v];
if (cur[u].size() < cur[v].size()) swap(u, v);
for (int x : cur[v]) {
curres -= (-- hsh[get(info[x])]);
info[x].second = u;
curres += (hsh[get(info[x])] ++);
cur[u].push_back(x); bel[x] = u;
}
while (j) {
if (res1[j] + res2[i] - curres >= K)
Ans = min(Ans, e1[j].w + e2[i].w), undo(j --);
else break;
}
}
cout << (Ans > (LL)(1e12) ? -1 : Ans) << "\n";
return 0;
}