#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <iomanip>
#include <limits>
#include <list>
#include <queue>
#include <tuple>
#include <map>
#include <stack>
#include <set>
using namespace std;
#define MOD (long long int)(1e9+7)
#define ll long long int
#define rep(i,n) for(int i=0; i<(int)(n); i++)
#define reps(i,n) for(int i=1; i<=(int)(n); i++)
#define REP(i,n) for(int i=n-1; i>=0; i--)
#define REPS(i,n) for(int i=n; i>0; i--)
#define INF (int)(1123456789)
#define LINF (long long int)(112345678901234567)
#define chmax(a, b) a = (((a)<(b)) ? (b) : (a))
#define chmin(a, b) a = (((a)>(b)) ? (b) : (a))
#define all(v) v.begin(), v.end()

const int N = (int)3e5;

ll mpow(ll a, ll b){
	if(b==0) return 1;
	else if(b%2==0){ll memo = mpow(a,b/2); return memo*memo%MOD;}
	else return mpow(a,b-1) * a % MOD;
}
ll gcd(ll a, ll b){
	if(b==0) return a;
	else return gcd(b, a%b);
}
vector<ll> kaijo_memo;
ll kaijo(ll n){
	if(kaijo_memo.size() > n) return kaijo_memo[n];
	if(kaijo_memo.size() == 0) kaijo_memo.push_back(1);
	while(kaijo_memo.size() <= n) kaijo_memo.push_back(kaijo_memo[kaijo_memo.size()-1] * kaijo_memo.size() % MOD);
	return kaijo_memo[n];
}
ll nCr(ll n, ll r){
	if(n < r || r < 0) return 0;
	ll ret = 1;
	ret *= kaijo(n); ret %= MOD;
	ret *= mpow(kaijo(r), MOD-2); ret %= MOD;
	ret *= mpow(kaijo(n-r), MOD-2); ret %= MOD;
	return ret;
}

struct node{ll r,c,a,id;};
vector<int> parent;
vector<int> size;
vector<int> retu;

int find(int a){
	if(parent[a] == a){
		return a;
	}else{
		return parent[a] = find(parent[a]);
	}
}

void unite(int a, int b){
	int pa = find(a), pb = find(b);
	if(pa == pb) return;
	size[pa] += size[pb];
	retu[pa] += retu[pb] - 1;
	parent[pb] = pa;
}

int main(void){
	ll n,h,w;cin>>n>>h>>w;
	rep(i,n){
		parent.push_back(i);
		size.push_back(1);
		retu.push_back(2);
	}
	vector<node> node_a, node_c, node_r;
	rep(i,n){
		ll r,c,a;
		cin>>r>>c>>a;
		node_a.push_back({r,c,a,-1});
	}
	sort(all(node_a), [](const node &x, const node &y){return x.a > y.a;});
	rep(i,n){
		node_a[i].id = i;
	}

	map<int ,node> Y,X;
	cerr<<endl;

	ll ans = 0;
	rep(i, node_a.size()){
		node next = node_a[i];
		ll r = next.r;
		ll c = next.c;
		ll a = next.a;

		node ny,nx;
		if(Y.count(r) > 0){
			ny = Y[r];
		}else{
			ny = next;
		}
		if(X.count(c) > 0){
			nx = X[c];
		}else{
			nx = next;
		}
		cerr<<ny.id<<" "<<nx.id<<" "<<next.r<<" "<<next.c<<" "<<size[ny.id]<<" "<<size[nx.id]<<endl;;
		if(find(ny.id) == find(nx.id) && find(ny.id) != next.id){//同一と合体
			if(size[find(ny.id)] + size[next.id] > retu[find(ny.id)]) continue;
		}
		if(find(ny.id) != find(nx.id) && find(ny.id) != next.id && find(nx.id) != next.id){//2つと合体
			if(size[find(ny.id)] + size[find(nx.id)] + 1 > retu[find(ny.id)] + retu[find(nx.id)]) continue;
		}

		bool douitu = find(ny.id) == find(nx.id) && find(ny.id) != next.id;

		unite(next.id, nx.id);
		unite(next.id, ny.id);
		if(douitu){
			retu[find(next.id)]--;
		}
		ans += next.a;
		Y[r] = next;
		X[c] = next;
		cerr<<next.r<<","<<next.c<<": "<<size[find(next.id)]<<" "<<retu[find(next.id)]<<endl;
	}
	cerr<<endl;
	cout<<ans<<endl;

	return 0;
}


Measured memory_bytes: 20192