#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;


template <typename Value, typename BinaryOp>
class valued_union_find_tree
{
  int                n;
  std::vector<Value> table;
  std::vector<int>   prt;
  BinaryOp           op;
  Value              id;

public:
  valued_union_find_tree (int n, BinaryOp op, Value id, Value init) :
    n(n), table(n, init), prt(n, -1), op(op), id(id)
    {}

  bool is_root (int x)        const {return prt.at(x) < 0;}
  int  size    (int x)        const {return -prt.at(find(x));}
  bool same    (int x, int y) const {return find(x) == find(y);}
  int  find    (int x)        const
  {
    while (!is_root(x)) x = prt.at(x);
    return x;
  }
  auto collect ()             const {return prt;}

  // Returns `true` if x and y are newly connected.
  // y becomes the partent.
  bool unite   (int x, int y)
  {
    if ((x = find(x)) == (y = find(y))) return false;
    if (size(x) > size(y)) std::swap(x, y);
    prt.at(y) += prt.at(x);
    prt.at(x) = y;
    table.at(y) = op(table.at(y), table.at(x));
    table.at(x) = id;
    return true;
  }

  auto get     (int x)        const {return table.at(find(x));}
  auto collect_vals ()        const
  {
    std::vector<Value> ret(n);
    for (auto i = 0; i < n; i++)
    {
      ret.at(i) = get(i);
    }
    return ret;
  }
  void set     (int x, Value val)    {table.at(find(x)) = val;}
  void add     (int x, Value val)    {set(x, get(x) + val);}
};

template <typename Value, typename BinaryOp>
auto make_valued_union_find_tree(int n, BinaryOp op, Value id, Value init)
{
  return valued_union_find_tree<Value, BinaryOp>(n, op, id, init);
}

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 uf = make_valued_union_find_tree
  (
    h + w,
    [](auto x, auto y){return x + y + 1;},
    0,
    0
  );
  std::sort(queries.begin(), queries.end());
  std::reverse(queries.begin(), queries.end());
  auto sat = [&] (int x) -> bool
  {
    auto dif = uf.get(x) - uf.size(x);
    assert(dif == -1 || dif == 0);
    return dif == 0;
  };
  lint ret = 0;
  for (auto tuple : queries)
  {
    int a, x, y;
    std::tie(a, x, y) = tuple;
    if (!uf.same(x, y) && (!sat(x) || !sat(y)))
    {
      uf.unite(x, y);
      ret += a;
    }
    else if (uf.same(x, y) && !sat(x))
    {
      assert(!sat(y));
      uf.set(y, uf.get(y) + 1);
      ret += a;
    }
  }
  std::cout << ret << std::endl;
  return 0;
}

Measured memory_bytes: 2944