#include #include #include #include #include #include #include #include #include #define REP(i, n) for(int i = 0;i < n;i++) #define REPR(i, n) for(int i = n;i >= 0;i--) #define FOR(i, m, n) for(int i = m;i < n;i++) #define FORR(i, m, n) for(int i = m;i >= n;i--) #define SORT(v, n) sort(v, v+n); #define VSORT(v) sort(v.begin(), v.end()); #define llong long long #define pb(a) push_back(a) #define INF 999999999 using namespace std; typedef pair P; typedef pair LP; typedef pair PP; typedef pair LPP; typedef long long int ll; #define ARRAY_MAX 100005 vector par(ARRAY_MAX);//親 vector ran(ARRAY_MAX);//木の深さ bool used[ARRAY_MAX];//使ったかどうか typedef struct edge{ ll num; ll u; ll v; ll cost; }EDGE; bool comp(const EDGE& e1,const EDGE& e2){ return e1.cost < e2.cost; } //n要素で初期化 void init(ll n){ for(ll i = 0;i < n;i++){ par[i] = i;/*各ノードに番号を振る,この時par[x]=xとなる時は木の根となる*/ ran[i] = 0;/*各ノード自体の高さは0*/ } } //木の根を求める int find(ll x){ if(par[x] == x){ return x;/*根ならそのノードの番号を返す*/ }else{ return par[x] = find(par[x]);/*根でないならさらにノードの根を探す*/ } } //xとyの属する集合を併合する void unite(ll x,ll y){ x = find(x);//xの根の番号を探す y = find(y);//yの根の番号を探す if(x == y){//一致すればつながっている return; } if(ran[x] < ran[y]){//xの高さが低いなら高いほうにつなぐ、そして高さは大きい方(y)になる par[x] = y; }else{ par[y] = x;//yの高さが低いなら高いほうにつなぐ、そして高さは大きいほう(x)になる if(ran[x] == ran[y]){//高さが一致しているなら併合の高さは1増える ran[x]++; } } } //xとyが同じ集合に属するか判定 bool same(ll x,ll y){ return find(x) == find(y);//同じ集合なら1、違うなら0が返る } int kruskal(ll n,ll count,vector& es,ll ans){ sort(es.begin(),es.end(),comp);//小さいほうから ll res = ans; for(ll i = 0;i < count;i++){ EDGE e = es[i]; if(used[e.num] == true){ //すでに数えた continue; } if(!same(e.u,e.v)){ //つなぐ unite(e.u,e.v); used[e.num] = true; res += e.cost; } } return res; } /*最小全域木をクラスカル法で実装*/ int main(){ ll n,m,k; cin >> n >> m >> k; vector es; vector es2; ll count = 0; ll a,b,c; ll sum = 0;//全経路の合計コスト ll use[k]; ll ans = 0; init(n); for(ll i = 0;i < m;i++){ cin >> a >> b >> c; a--; b--; sum += c; EDGE e; e.num = i; e.u = a; e.v = b; e.cost = c;/*昇順ソート済み*/ es.push_back(e); es2.push_back(e); } //mapの作成 REP(i,ARRAY_MAX){ used[i] = false; } //閉鎖できない経路 for(ll i = 0;i < k;i++){ cin >> use[i]; use[i]--; unite(es[use[i]].u,es[use[i]].v);//先につないでおく ans += es[use[i]].cost; used[use[i]] = true; } ans = kruskal(n,m,es,ans);//最小全域木作成 cout << sum - ans << endl; return 0; }