[20200717NOIP提高组模拟T3]水管

题目大意:

  给你$n$个点和$m$条边,要求你输出最小生成树的边权之和并判断最小生成树是否唯一.

solution:

  最小生成树板子,Kruskal即可.至于判断唯一性,这里有一种耐人寻味的解法.对于每一个边权值$z$,我们可以寻找所有边权与其相等的边并统计其中合法边数sum,然后再扫描一次选其中足够的合法边并加入最小生成树,如果有剩余的合法边,则说明可以替换,即最小生成树不唯一.

code:

  

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next exnt
#define debug puts("mlg")
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void writesp(ll x);
inline void writeln(ll x);
inline void write(ll x);
ll T;
ll n,m;
struct node{
    ll X,Y,Z;
}t[220000];
inline bool cmp(node x,node y){
    return x.Z<y.Z;
}
ll f[220000];
inline void init(){
    for(R ll i=1;i<=n;i++) f[i]=i;
}
inline ll getf(ll x){
    return f[x]==x?x:f[x]=getf(f[x]);
}
inline bool check(ll x,ll y){
    return getf(x)==getf(y);
}
inline void merge(ll x,ll y){
    f[getf(y)]=getf(x);
}
ll sum,total,ans;
int main(){
    T=read();
    while(T--){
        n=read(),m=read();
        init();
        for(R ll i=1;i<=m;i++) t[i].X=read(),t[i].Y=read(),t[i].Z=read();
        sort(t+1,t+m+1,cmp);
        total=ans=sum=0;
        for(R ll i=1;i<=m;i++){
            for(R ll j=i;j<=m&&t[j].Z==t[i].Z;j++){
                if(!check(t[j].X,t[j].Y)){
                    ++sum;
                }
            }
            do{
                if(!check(t[i].X,t[i].Y)){
                    merge(t[i].X,t[i].Y);
                    ans+=t[i].Z;
                    ++total;
                }
                if(total==n-1) break;
                ++i;
            }while(t[i].Z==t[i-1].Z&&i<=m);
            if(total==n-1) break;
            --i;
            
        }
        writeln(ans);
        if(sum>n-1) puts("No");
        else puts("Yes");
    }
}
inline ll read(){
    ll x=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') t=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*t;
}
inline void write(ll x){
    if(x<0){putchar('-');x=-x;}
    if(x<=9){putchar(x+'0');return;}
    write(x/10);putchar(x%10+'0');
}
inline void writesp(ll x){
    write(x);putchar(' ');
}
inline void writeln(ll x){
    write(x);putchar('\n');
}

感谢机房神犇zxt提供思路

posted @ 2020-07-17 17:21  月落乌啼算钱  阅读(122)  评论(0编辑  收藏  举报