zoukankan      html  css  js  c++  java
  • [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('
    ');
    }

    感谢机房神犇zxt提供思路

  • 相关阅读:
    IOS开发中针对UIImageView的几种常用手势
    VIew中的触摸事件 touchBegin 等一系列方法
    控制器的跳转-modal与push
    终于决定把自己的小窝从CSDN搬到博客园了
    UIView的frame和bounds区别
    android中数据存储的contentprovider的使用方法
    android中Json数据保存方式
    android手机操作SD的使用方法
    android手机中图片的拖拉及浏览功能
    android图片切换ImageSwichter的动画切换效果
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13331397.html
Copyright © 2011-2022 走看看