题解 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;
}


posted @ 2024-10-30 22:12  caijianhong  阅读(36)  评论(0编辑  收藏  举报