CF160D Edges in MST

题意

给你一张联通无向图,没有自环和重边。
问每一条边是:

  1. 在所有MST中(输出"any");
  2. 在至少一个MST中(输出"at least one");
  3. 不在任何MST中(输出"none")。

思路

利用kruskal的思想及证明(感性,严谨证明可看OI wiki),对于边权小的边应先加入MST中,因为如果这不是最优的,那么必然在原图中有另一条更短路连接这两个联通块,那么此边就不是最短边了。

于是就可以对不同的边权值分层。
然后对于同一层的边有三种情况:

  1. 两端连接同一联通块,代表这条边不会出现在MST中。
  2. 将当层的边加入图中后它是桥(割边),代表这条边一定出现在所有MST中。
  3. 不是上面两种情况,说明当层的所有边加入图中后组成了一个环,而环上的边是可以替代的,于是此状态代表出现在至少一个MST中。

所以一层一层加边先将同一层所有边加入图中并记录属于情况1的边,再用tarjan找桥记录属于情况2的边,最后将所有边加进DSU中。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<vector>
#define I inline
using namespace std;
const int Mx=1e5+5;
template<typename T>
T read(){
    T ans=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}
    return ans; 
}
int n,m;
int ans[Mx];
class DSU{
public:
    DSU(){
        for(int i=1;i<Mx;i++)f[i]=i;
    }
    I void u(int x,int y){
        f[x]=y;
    }
    I int a(int x){
        if(f[x]==x)return x;
        return f[x]=a(f[x]);
    }
private:
    int f[Mx];
}U;
class Graph{
public:
    I void Main(){
        sort(edge+1,edge+1+tot);
        for(int i=1;i<=tot;i++)
            if(etop==0||edge[i].v==edge[i-1].v)E[++etop]=i;
            else{
                kruskal();
                etop=1;
                E[etop]=i;
            }
        kruskal();
    }
    I void addEdge(int v,int x,int y){
        edge[++tot]=(Edge){x,y,v,tot};
    }
private:
    struct Node{
        vector<int>link;
        int dfn,low,fir;
    }node[Mx];
    struct Edge{
        int as,bs,v,id;
        friend bool operator <(Edge a,Edge b){return a.v<b.v;}
    }edge[Mx];
    int tot,E[Mx<<1],etop,N[Mx<<1],ntop,num;

    I void tarjan(int x,int from){
        node[x].dfn=node[x].low=++num;
        for(int &i=node[x].fir;i<node[x].link.size();i++){
            int p=node[x].link[i];
            if(p==from)continue;
            int v=edge[p].as+edge[p].bs-x;
            if(!node[v].dfn){
                tarjan(v,p);
                node[x].low=min(node[x].low,node[v].low);
                if(node[v].low==node[v].dfn)ans[edge[p].id]=1;
            }else node[x].low=min(node[x].low,node[v].dfn);

        }
    }

    I void kruskal(){
        ntop=0;
        for(int i=1;i<=etop;i++){
            int x=U.a(edge[E[i]].as),y=U.a(edge[E[i]].bs);
            if(x==y){
                ans[edge[E[i]].id]=2;
                continue;
            }
            edge[E[i]].as=x;edge[E[i]].bs=y;
            node[x].link.push_back(E[i]);
            node[y].link.push_back(E[i]);
            node[x].dfn=node[x].low=0;
            node[y].dfn=node[y].low=0;
            N[++ntop]=x;
            N[++ntop]=y;
        }
        for(int i=1;i<=ntop;i++)
            if(node[N[i]].dfn==0)num=0,tarjan(N[i],0);
        for(int i=1;i<=etop;i++){
            int x=U.a(edge[E[i]].as),y=U.a(edge[E[i]].bs);
            if(x!=y)U.u(x,y);
        }
    }
}G;
int main(){
    n=read<int>(),m=read<int>();
    for(int i=1;i<=m;i++)G.addEdge(read<int>(),read<int>(),read<int>()),ans[i]=0;
    G.Main();
    for(int i=1;i<=m;i++){
        switch(ans[i]){
            case 0:puts("at least one");break;
            case 1:puts("any");break;
            case 2:puts("none");break;
        }
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值