題目描述
地主的傻兒子豆豆家很大很大,由很多個區域組成。其中有不少封閉的區域,豆豆覺得很不爽於是決定拆牆,把家打通使得他可以訪問到每一個區域(包括家外面無限大的區域)。我們用 N 個端點和 M 條邊來描述豆豆的家。第 i 個端點的座標爲(xi,yi),第 i 條邊連接端點 Ai 和 Bi,拆除所需要花費的力氣爲 Ci 。保證所有邊只在端點相交,也就是這是一個平面圖,也沒有重邊和自環。
現在豆豆想知道他最少一共需要花費多少力氣?
輸入格式
第一行一個整數 T 表示數據組數。
每組數據第一行兩個整數 N,M 。
接下來 N 行每行兩個整數 Xi 和 Yi。
接下來 M 行每行三個整數 Ai,Bi,Ci。
輸出格式
每組數據輸出兩個整數表示最少拆除的牆的數量和拆牆最少需要多少的力氣。注意所有牆可能不互相連通。
樣例數據 1
輸入
1
4 4
-1 -1
-1 1
1 1
1 -1
1 2 1
2 3 2
3 4 1
4 1 2
輸出
1 1
備註
【數據範圍】
對於 30% 的數據,N,M≤10,T=10;
對於 70% 的數據,N≤5000, M≤10000,T=1;
對於 100% 的數據,N≤100000;M≤200000;ΣN≤300000;ΣM≤500000;|xi|,|yi|≤100000;0≤wi≤10000,T=3。
看完題,居然是求最大生成森林,再看一眼T2,來先把T2的暴力打了,然後不知不覺過了兩個半小時,還沒有調出來,導致這道板子題都沒打,不得不說考試的時候應該選擇一個正確的做題策略;
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<string>
#include<cctype>
#define N 100005
#define M 200010
using namespace std;
int T,n,m,x,y,sum,sumtree,tot,fa[N];
struct Node{
int st,to,w;
bool operator < (const Node&a) const{
return w>a.w;
}
}edge[M];
inline void init(){
sum=sumtree=tot=0;
for(int i=1;i<=n;i++) fa[i]=i;
memset(edge,0,sizeof(edge));
}
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
inline int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}
int main(){
// freopen("lx.in","r",stdin);
T=Readint();
while(T--){
n=Readint(),m=Readint();init();
for(int i=1;i<=n;i++){x=Readint(),y=Readint();}
for(int i=1;i<=m;i++){edge[i].st=Readint(),edge[i].to=Readint(),edge[i].w=Readint();sum+=edge[i].w;}
sort(edge+1,edge+1+m);
for(int i=1;i<=m;i++){
int fx=find(edge[i].st),fy=find(edge[i].to);
if(fx!=fy){
fa[fx]=fy;
sumtree+=edge[i].w;
tot++;
}
if(tot==n-1) break;
}
cout<<m-tot<<" "<<sum-sumtree<<endl;
}
return 0;
}