#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{ int num; int u; int v; int cost; }EDGE; typedef struct where{ int num; int x; int y; }WHERE; bool comp(const EDGE& e1,const EDGE& e2){ return e1.cost < e2.cost; } //n要素で初期化 void init(int n){ for(int i = 0;i < n;i++){ par[i] = i;/*各ノードに番号を振る,この時par[x]=xとなる時は木の根となる*/ ran[i] = 0;/*各ノード自体の高さは0*/ } } //木の根を求める int find(int x){ if(par[x] == x){ return x;/*根ならそのノードの番号を返す*/ }else{ return par[x] = find(par[x]);/*根でないならさらにノードの根を探す*/ } } //xとyの属する集合を併合する void unite(int x,int 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(int x,int y){ return find(x) == find(y);//同じ集合なら1、違うなら0が返る } int kruskal(int n,int count,vector& es,int ans){ sort(es.begin(),es.end(),comp); int res = ans; for(int i = 0;i < count;i++){ EDGE e = es[i]; if(used[e.num] == true){ //cout << e.num << endl; continue; } if(!same(e.u,e.v)){ unite(e.u,e.v); used[e.num] = true; res += e.cost; } } return res; } /*最小全域木をクラシカル法で実装*/ /*ABC065 AC解法*/ int main(){ int n,m,k; cin >> n >> m >> k; vector es; vector es2; vector map(n); int count = 0; int a,b,c; int sum = 0;//全経路の合計コスト int use[k]; int ans = 0; init(n); REP(i,m){ 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; } //閉鎖できない経路 REP(i,k){ cin >> use[i]; use[i]--; unite(es[use[i]].u,es[use[i]].v); ans += es[use[i]].cost; used[use[i]] = true; } /*cout << ans << endl; REP(i,n){ cout << par[i] << " "; } cout << endl;*/ ans = kruskal(n,m,es,ans);//最小全域木作成 //cout << sum << endl; //cout << ans << endl; cout << sum - ans << endl; return 0; }