Problem p01090 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
using Int = long long;

struct Kruskal {

  struct UnionFind {
    Int n;
    vector<Int> r, p;
    UnionFind() {}
    UnionFind(Int sz) : n(sz), r(sz, 1), p(sz, 0) {
      iota(p.begin(), p.end(), 0);
    }
    Int find(Int x) { return (x == p[x] ? x : p[x] = find(p[x])); }
    bool same(Int x, Int y) { return find(x) == find(y); }
    void unite(Int x, Int y) {
      x = find(x);
      y = find(y);
      if (x == y)
        return;
      if (r[x] < r[y])
        swap(x, y);
      r[x] += r[y];
      p[y] = x;
    }
  };

  struct edge {
    Int from, to;
    double cost;
    Int used;
    char color;
    edge() {}
    edge(Int from, Int to, double cost, char color)
        : from(from), to(to), cost(cost), used(0), color(color) {}
    bool operator<(const edge &e) const { return cost < e.cost; }
  };

  Int n;
  vector<edge> edges;

  Kruskal() {}
  Kruskal(Int sz) : n(sz) {}

  Int build(Int k = -1) {
    sort(edges.begin(), edges.end());
    UnionFind uf(n + 1);
    double res = 0;
    Int cnt = 0;
    for (Int i = 0; i < (Int)edges.size(); i++) {
      edge &e = edges[i];
      if (!uf.same(e.from, e.to)) {
        e.used = 1;
        res += e.cost;
        uf.unite(e.from, e.to);
        cnt++;
      }
    }
    if (cnt + 1 != n)
      return -1;
    return res;
  }
};

signed main() {
  Int n, m, k;
  while (cin >> n >> m >> k, n) {
    Kruskal kr(n);
    auto edges = kr.edges;
    for (Int i = 0; i < m; i++) {
      Int u, v, w;
      char c;
      cin >> u >> v >> w >> c;
      u--;
      v--;
      edges.emplace_back(u, v, w, c);
    }
    double ub = 1e12, ans;
    auto check = [&](double x) {
      x -= ub;
      kr = Kruskal(n);
      for (auto e : edges) {
        if (x > 0 && e.color == 'A')
          e.cost += x;
        if (x < 0 && e.color == 'B')
          e.cost -= x;
        kr.edges.emplace_back(e);
      }

      ans = kr.build();
      if (ans < 0)
        return Int(-1);
      if (x > 0)
        ans -= x * k;
      if (x < 0)
        ans += x * (n - 1 - k);

      Int res = 0;
      for (auto e : kr.edges)
        res += (e.used && e.color == 'A');
      return res;
    };
    double l = 0, r = 2 * ub;
    if (check(l) < k || check(r) > k) {
      cout << -1 << endl;
      continue;
    }
    for (Int i = 0; i < 2000; i++) {
      double m = (l + r) / 2;
      if (check(m) >= k)
        l = m;
      else
        r = m;
    }
    check(l);
    assert(check(l) == k);
    cout << (Int)round(ans) << endl;
  }
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
using Int = long long;

struct Kruskal {

  struct UnionFind {
    Int n;
    vector<Int> r, p;
    UnionFind() {}
    UnionFind(Int sz) : n(sz), r(sz, 1), p(sz, 0) {
      iota(p.begin(), p.end(), 0);
    }
    Int find(Int x) { return (x == p[x] ? x : p[x] = find(p[x])); }
    bool same(Int x, Int y) { return find(x) == find(y); }
    void unite(Int x, Int y) {
      x = find(x);
      y = find(y);
      if (x == y)
        return;
      if (r[x] < r[y])
        swap(x, y);
      r[x] += r[y];
      p[y] = x;
    }
  };

  struct edge {
    Int from, to;
    double cost;
    Int used;
    char color;
    edge() {}
    edge(Int from, Int to, double cost, char color)
        : from(from), to(to), cost(cost), used(0), color(color) {}
    bool operator<(const edge &e) const { return cost < e.cost; }
  };

  Int n;
  vector<edge> edges;

  Kruskal() {}
  Kruskal(Int sz) : n(sz) {}

  Int build(Int k = -1) {
    sort(edges.begin(), edges.end());
    UnionFind uf(n + 1);
    double res = 0;
    Int cnt = 0;
    for (Int i = 0; i < (Int)edges.size(); i++) {
      edge &e = edges[i];
      if (!uf.same(e.from, e.to)) {
        e.used = 1;
        res += e.cost;
        uf.unite(e.from, e.to);
        cnt++;
      }
    }
    if (cnt + 1 != n)
      return -1;
    return res;
  }
};

signed main() {
  Int n, m, k;
  while (cin >> n >> m >> k, n) {
    Kruskal kr(n);
    auto edges = kr.edges;
    for (Int i = 0; i < m; i++) {
      Int u, v, w;
      char c;
      cin >> u >> v >> w >> c;
      u--;
      v--;
      edges.emplace_back(u, v, w, c);
    }
    double ub = 1e12, ans;
    auto check = [&](double x) {
      x -= ub;
      kr = Kruskal(n);
      for (auto e : edges) {
        if (x > 0 && e.color == 'A')
          e.cost += x;
        if (x < 0 && e.color == 'B')
          e.cost -= x;
        kr.edges.emplace_back(e);
      }

      ans = kr.build();
      if (ans < 0)
        return Int(-1);
      if (x > 0)
        ans -= x * k;
      if (x < 0)
        ans += x * (n - 1 - k);

      Int res = 0;
      for (auto e : kr.edges)
        res += (e.used && e.color == 'A');
      return res;
    };
    double l = 0, r = 2 * ub;
    if (check(l) < k || check(r) > k) {
      cout << -1 << endl;
      continue;
    }
    for (Int i = 0; i < 2000; i++) {
      double m = (l + r) / 2;
      if (check(m) >= k)
        l = m;
      else
        r = m;
    }
    check(l);
    cout << (Int)ceil(ans) << endl;
  }
  return 0;
}