题解 QOJ7069【[Yinchuan20] Farm】/ SS241030C【桥梁】
题目描述
潇杻国是一个水上之国,它的每座城市都是一个小岛。
近日,潇杻国国王柬鋀打算修筑若干座桥梁连接这 \(n\) 座城市。潇杻国的桥梁设计师给出了 \(m\) 个桥梁建造方案,第 \(i\) 个建造方案可以连接第 \(u_i\) 座城市与第 \(v_i\) 座城市,需要花费 \(c_i\) 的代价。
由于潇杻国的桥梁设计师受到贿赂,对于建造方案的选择将会受到 \(q\) 条限制,第 \(i\) 条限制为在第 \(a_i\) 个与第 \(b_i\) 个两个建造方案中必须至少选择一个建造。
由于潇杻国国王柬鋀只会做计数题,所以你需要帮他求出连接所有城市的最小代价,如果无论如何都无法连接所有桥梁,输出 mumuyibarenkoumumumu
。
对于所有测试数据,\(1\leq n\leq 10^5,1\leq m\leq 5\times 10^5,1\leq c_i\leq 10^3,0\leq q\leq 16\)。
题解
这个 \(2^q\) 肯定是躲不过的了……所以只能缩小信息量。忘了怎么想的了,不演了,直接说结论,先跑最小生成树,判断无解,将涉及到的 \(4q\) 个点拿出来建虚树,将虚树边对应的直链上的边权最大的边拿出来踢出最小生成树,然后扔进另外一个集合中。暴力枚举每个限制用谁去满足,然后强制选上这些边后再用刚才那个集合的边跑最小生成树,然后加上前面第一次最小生成树没被扔掉的边的边权和去更新答案。复杂度算不清楚。
我的天啊,std 更好理解一点,就是题解有错误结论,来个大神 https://www.cnblogs.com/liyixin0514/p/18516714
code
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
template <int N>
struct dsu {
int fa[N + 10], siz[N + 10];
void init(int n) { for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1; }
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
bool merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) return false;
if (siz[x] < siz[y]) swap(x, y);
siz[x] += siz[y], fa[y] = x;
return true;
}
};
struct edge {
int u, v, w;
bool operator<(const edge& rhs) const { return w < rhs.w; }
};
int n, m, q;
edge e[500010];
int lim[20][2];
edge rlim[20][2];
dsu<500010> dsy;
vector<edge> g[500010];
int kruskal(bool op = false) {
int ans = 0;
for (int i = 1; i <= m; i++) {
if (dsy.merge(e[i].u, e[i].v)) {
ans += e[i].w;
debug("link (%d, %d, %d)\n", e[i].u, e[i].v, e[i].w);
if (op) g[e[i].u].push_back(e[i]), g[e[i].v].push_back({e[i].v, e[i].u, e[i].w});
}
}
return ans;
}
int chs[20], fans = 2e9, vis[500010], tim, ans0, id[100010];
vector<int> key;
vector<edge> e0;
void dfs(int now) {
if (now == q + 1) {
int ans = 0;
dsy.init(key.size());
++tim;
for (int t = 1; t <= q; t++) {
if (exchange(vis[lim[t][chs[t]]], tim) == tim) continue;
auto ed = rlim[t][chs[t]];
dsy.merge(id[ed.u], id[ed.v]), ans += ed.w;
}
for (auto ed : e0) {
if (dsy.merge(ed.u, ed.v)) ans += ed.w;
}
fans = min(fans, ans);
return ;
}
chs[now] = 0;
dfs(now + 1);
if (lim[now][0] == lim[now][1]) return ;
chs[now] = 1;
dfs(now + 1);
}
int fa[19][100010], mxw[19][100010], dep[100010], dfn[100010], cnt;
bool cmp(int u, int v) { return dfn[u] < dfn[v]; }
void dfst(int u, int _fa) {
debug("dfst(%d, %d)\n", u, _fa);
fa[0][u] = _fa, dep[u] = dep[_fa] + 1, dfn[u] = ++cnt;
for (auto e : g[u]) if (e.v != _fa) debug("dfst u = %d, v = %d, w = %d\n", u, e.v, e.w), mxw[0][e.v] = e.w, dfst(e.v, u);
}
int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
for (int j = 18; j >= 0; j--) if (d >> j & 1) u = fa[j][u];
if (u == v) return u;
for (int j = 18; j >= 0; j--) if (fa[j][u] != fa[j][v]) u = fa[j][u], v = fa[j][v];
return fa[0][u];
}
int maxw(int u, int d) {
int res = -1;
for (int j = 18; j >= 0; j--) if (d >> j & 1) res = max(res, mxw[j][u]), u = fa[j][u];
return res;
}
int main() {
#ifndef LOCAL
#ifndef NF
freopen("bridge.in", "r", stdin);
freopen("bridge.out", "w", stdout);
#endif
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n >> m;
for (int i = 1; i <= m; i++) cin >> e[i].u >> e[i].v >> e[i].w;
cin >> q;
for (int i = 1, x, y; i <= q; i++) {
cin >> x >> y, lim[i][0] = x, lim[i][1] = y, rlim[i][0] = e[x], rlim[i][1] = e[y];
key.push_back(e[x].u);
key.push_back(e[x].v);
key.push_back(e[y].u);
key.push_back(e[y].v);
}
sort(e + 1, e + m + 1);
dsy.init(n);
ans0 = kruskal(true);
for (int i = 1; i <= n; i++) if (dsy.find(i) != dsy.find(1)) return cout << "mumuyibarenkoumumumu" << endl, 0;
dfst(1, 0);
for (int j = 1; j <= 18; j++) {
for (int i = 1; i <= n; i++) fa[j][i] = fa[j - 1][fa[j - 1][i]];
for (int i = 1; i <= n; i++) mxw[j][i] = max(mxw[j - 1][i], mxw[j - 1][fa[j - 1][i]]);
}
if (q) {
{
auto bg = begin(key), ed = end(key);
sort(bg, ed, cmp), key.erase(unique(bg, ed), ed);
int m = key.size();
key.resize(m * 2 - 1);
for (int i = 1; i < m; i++) key[i + m - 1] = lca(key[i], key[i - 1]);
bg = begin(key), ed = end(key);
sort(bg, ed, cmp), key.erase(unique(bg, ed), ed);
tim = 0;
for (int p : key) id[p] = ++tim;
for (int i = 1; i < (int)key.size(); i++) {
debug("lca(%d, %d) = %d\n", key[i], key[i - 1], lca(key[i], key[i - 1]));
int u = key[i], v = lca(key[i], key[i - 1]);
debug("vt (%d, %d)\n", u, v);
e0.push_back({id[u], id[v], maxw(u, dep[u] - dep[v])});
}
}
for (auto e : e0) ans0 -= e.w, debug("- (%d, %d, %d)\n", e.u, e.v, e.w);
sort(e0.begin(), e0.end());
dfs(1);
} else fans = 0;
cout << fans + ans0 << endl;
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18516713/solution-SS241030C