importjava.util.ArrayList;importjava.util.Comparator;importjava.util.PriorityQueue;importjava.util.Scanner;publicclassSolution{staticintN,E;// 정점 수, 간선 수staticint[]parent;// disjoint-set에서 각 정점의 부모(대표자) 정보 저장하는 배열staticboolean[]visit;// 선택한 정점 재방문 안할 때 쓰는 배열staticArrayList<Edge>mst;staticPriorityQueue<Edge>pq;publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intT=sc.nextInt();for(inttc=1;tc<=T;tc++){N=sc.nextInt();E=sc.nextInt();visit=newboolean[N+1];parent=newint[N+1];pq=newPriorityQueue<>(newEdgeComparator());mst=newArrayList<>();for(inte=0;e<E;e++){intst=sc.nextInt();intend=sc.nextInt();intvalue=sc.nextInt();pq.add(newEdge(st,end,value));// 간선들을 가중치로 정렬하는 우선순위 큐에 다 집어넣기.}kruskal();longsum=0;for(inti=0;i<mst.size();i++){sum+=mst.get(i).value;}System.out.println("#"+tc+" "+sum);}}staticvoidkruskal(){for(inti=1;i<=N;i++){// 일단 모든 정점들은 각각 다 대표로 만들어진다parent[i]=i;}for(inti=0;i<E;i++){Edgeedge=pq.poll();// 가중치 작은 순서대로 간선이 나옴if(find(edge.start)==find(edge.end)){// 간선의 대표자가 같으면 사이클이 생기므로 스킵. continue;}union(edge.start,edge.end);//사이클이 안생기는 간선의 양 접점을 하나로 합병mst.add(edge);// 선택된 간선을 mst에 추가}}// 특정 원소가 포함된 집합의 대표자 찾기 메소드staticintfind(intn){if(parent[n]==n){returnn;}parent[n]=find(parent[n]);// find가 실행되는 시점의 소속집합 전체의 대표자를 부모로 기억시켜서 효율성 증가.returnparent[n];}// n1과 n2가 소속된 두 집합을 합병하는 메소드staticvoidunion(intn1,intn2){intp1=find(n1);intp2=find(n2);if(p1!=p2){// 두 집합의 대표자가 다른 경우 합병 진행parent[p1]=p2;}}// 우선순위 큐가 간선들을 가중치 순으로 줄세울 수 있게 해주는 비교기능 내장 클래스staticclassEdgeComparatorimplementsComparator<Edge>{@Overridepublicintcompare(Edgeo1,Edgeo2){returno1.value>o2.value?1:-1;}}// 하나의 간선정보를 하나의 객체에 묶기 위한 내부 클래스.staticclassEdge{intstart,end,value;Edge(ints,inte,intv){start=s;end=e;value=v;}}}