#include <bits/stdc++.h>
#define loop(n) for (int ngtkana_is_genius = 0; ngtkana_is_genius < int(n); ngtkana_is_genius++)
#define rep(i, begin, end) for(int i = int(begin); i < int(end); i++)
#define lint long long
auto cmn = [](auto& a, auto b){if (a > b) {a = b; return true;} return false;};
auto cmx = [](auto& a, auto b){if (a < b) {a = b; return true;} return false;};
void debug_impl() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail){
  std::cerr << " " << head;
  debug_impl(tail...);
}
#define debug(...) std::cerr << std::boolalpha << "[" << #__VA_ARGS__ << "]:";\
  debug_impl(__VA_ARGS__);\
  std::cerr << std::noboolalpha;

class quick_find
{
public:
  using size_type          = int;
  using node_type          = int;
  using group_type         = int;
  using group_array_type   = std::vector<node_type>;
  using members_array_type = std::vector<std::vector<node_type>>;

private:
  size_type          n;
  group_array_type   leader;
  members_array_type members;

public:
  quick_find (size_type n) : n(n), leader(n), members(n)
  {
    for (int i = 0; i < n; i++) {
      leader.at(i) = i;
    }
    for (int i = 0; i < n; i++) {
      members.at(i) = {i};
    }
  }

  auto       collect ()             const {return leader;}

  bool       is_root (int x)        const {return find(x) == x;}

  size_type  size    (int x)        const {return members.at(x).size();}

  bool       same    (int x, int y) const {return find(x) == find(y);}

  group_type find    (int x)        const {return leader.at(x);}

  // Returns `true` if x and y are newly connected.
  bool unite   (int x, int y) {
    if ((x = find(x)) == (y = find(y))) return false;
    if (size(x) > size(y)) std::swap(x, y);
    for (auto child : members.at(x))
    {
      leader.at(child) = y;
      members.at(y).push_back(child);
    }
    std::decay_t<decltype(members.at(x))>{}.swap(members.at(x));
    return true;
  }
};

template <typename T>
std::istream& operator>> (std::istream& is, std::vector<T>& v)
{
  for (auto & x : v) is >> x;
  return is;
}

template <typename T>
std::ostream& operator<< (std::ostream& os, const std::vector<T>& v)
{
  auto n = v.size();
  os << "{";
  for (size_t i = 0; i < n; i++)
    os << (i > 0 ? "," : "") << v[i];
  return os << "}";
}

int main()
{
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int n, h, w;
  std::cin >> n >> h >> w;
  auto queries = std::vector<std::tuple<int, int, int>>(n);
  rep(i, 0, n)
  {
    int x, y, a;
    std::cin >> x >> y >> a;
    x--, y--, y += h;
    queries.at(i) = std::make_tuple(a, x, y);
  }
  auto qf = quick_find(h + w + 1);
  std::sort(queries.begin(), queries.end());
  std::reverse(queries.begin(), queries.end());
  auto base = h + w;
  lint ret = 0;
  for (auto tuple : queries)
  {
    int a, x, y;
    std::tie(a, x, y) = tuple;
    if (!qf.same(x, y) && (!qf.same(base, x) || !qf.same(base, y)))
    {
      qf.unite(x, y);
      ret += a;
    }
    else if (qf.same(x, y) && !qf.same(base, x))
    {
      assert(!qf.same(base, y));
      qf.unite(base, x);
      ret += a;
    }
  }
  std::cout << ret << std::endl;
  return 0;
}

Measured memory_bytes: 14588