#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
typedef long long int ll;

struct Edge{
    int to,from; ll cost;
    Edge(){}
    Edge(int to,int from,ll cost):to(to),from(from),cost(cost){}
};
bool operator<(const Edge& x,const Edge& y){
    return x.cost<y.cost;
}

struct UnionFind{
    vector<int> par,num;
    vector<bool> done;
    UnionFind(int n):par(n),num(n,1),done(n,false){
        iota(par.begin(),par.end(),0);  //include<numeric>
    }
    int find(int v){
        return (par[v]==v)?v:(par[v]=find(par[v]));
    }
    void unite(int u,int v){
        u=find(u),v=find(v);
        if(u==v)return;
        if(num[u]<num[v])swap(u,v);
        num[u]+=num[v];
        par[v]=u;
        done[u]=done[u]|done[v];
    }
    bool same(int u,int v){
        return find(u) == find(v);
    }
    bool ispar(int v){
        return v=find(v);
    }
    int size(int v){
        return num[find(v)];
    }
};

int main(){
    int n,h,w; cin >> n >> h >> w;
    vector<Edge> v;
    for(int i=0;i<n;i++){
        int r,c,a; cin >> r >> c >> a;
        r--; c--;
        v.push_back(Edge(r,c+h,a));
    }
    ll ans=0;
    sort(v.begin(),v.end());
    reverse(v.begin(),v.end());
    UnionFind uf(h+w);

    for(int i=0;i<n;i++){
        if(!uf.same(v[i].from,v[i].to)){
            if(uf.done[uf.find(v[i].from)]&&uf.done[uf.find(v[i].to)])continue;
            uf.unite(v[i].from,v[i].to);
            ans+=v[i].cost;
        }
        else{
            if(!uf.done[uf.find(v[i].from)]){
                uf.done[uf.find(v[i].from)]=true;
                ans+=v[i].cost;
            }
        }
    }
    cout << ans << endl;
}