Codeforces160D Edges in MST

来源:互联网 发布:图书管理系统java项目 编辑:程序博客网 时间:2024/05/17 02:02

传送门

题目大意

给定一幅n个节点m条边的无向连通简单图,判断图中的每一条边是一定在该图的任意一棵最小生成树中,还是不可能出现在最小生成树中,或者是无法确定.

2n105,n1mmin(105,n(n1)2).
边权范围1wi106.

题解

一个最初的想法就是先随便跑出一棵MST,然后考虑每条非树边对应的路径上是否有与其权值相等的边可以替换.
容易知道其实与考虑的非树边权值相等的边只可能为路径上权值最大的边.
然而这样的边可能有多条,树剖+线段树维护会比较麻烦,并没有去敲.
这样可以做到时间复杂度O(nlg2n),空间复杂度O(n).

然而还有一种更机智的做法,不过可能这里不好讲清楚,可以去看官方题解.
在进行Kruskal算法时,我们把所有权值相等的边同时考虑.其中如果有某条边的两个顶点已经属于一个连通块,那么这条边肯定不会加入MST中.
对于其他的边,它们单独的作用就是把两个连通块合并.不管这些边中具体哪些加入了MST中,它们最终的作用一定是把这些连通块全都合并起来了.如果一条边必须出现在MST中,那么就是说如果不加入这条边就不能把其中的两个连通块合并了.
是不是和图的连通性中的的概念很像?
所以方法就是把加入这些边之前的那些连通块看作点构建新图,dfs搜一遍求出桥后那些桥就是必须出现在MST中的边,否则就是无法确定.然后再把这些连通块合并.
这样做的时间复杂度除去给边排序和并查集之外是O(m)的,非常神奇.
具体实现可以看代码.

代码

#include<cstdio>#include<algorithm>using namespace std;const int N=1e5+5;int tot_edge,head[N],dfs_clock,pre[N],par[N],ans[N];// ans[i]=0:any 1:at least one 2:nonevoid rd(int &res){    res=0;    char c;    while(c=getchar(),c<48);    do res=(res<<3)+(res<<1)+(c^48);        while(c=getchar(),c>47);}struct EDGE{    int u,v,cost,id;    inline void Rd(){        rd(u);rd(v);rd(cost);    }    inline bool operator <(const EDGE &tmp)const{        return cost<tmp.cost;    }}es[N];struct Edge{    int to,nxt,id;}edge[N<<1];void add_edge(int u,int v,int id){    edge[tot_edge]=(Edge){v,head[u],id};    head[u]=tot_edge++;}int get_root(int x){    return par[x]==x?x:par[x]=get_root(par[x]);}inline void Min(int &a,int b){    if(b<a)a=b;}int dfs(int u,int id){    int lowu=pre[u]=++dfs_clock;    for(int i=head[u];~i;i=edge[i].nxt){        int v=edge[i].to;        if(!pre[v]){            int lowv=dfs(v,i);            Min(lowu,lowv);            if(lowv>pre[u])ans[edge[i].id]=0;        }        else if(pre[v]<pre[u]&&i!=(id^1)){            Min(lowu,pre[v]);        }    }    return lowu;}void unite(int u,int v){    u=get_root(u);    v=get_root(v);    if(u==v)return;    par[u]=v;}int main(){    int n,m;    rd(n);rd(m);    for(int i=1;i<=n;++i)        par[i]=i;    for(int i=0;i<m;++i){        es[i].Rd();        es[i].id=i;    }    sort(es,es+m);    for(int i=0;i<m;){        int j=i;        while(j+1<m&&es[j+1].cost==es[j].cost)++j;        tot_edge=dfs_clock=0;        for(int k=i;k<=j;++k){            es[k].u=get_root(es[k].u);            es[k].v=get_root(es[k].v);            int u=es[k].u,v=es[k].v;            head[u]=head[v]=-1;            pre[u]=pre[v]=0;        }        for(int k=i;k<=j;++k){            int u=es[k].u,v=es[k].v,id=es[k].id;            if(u==v){                ans[id]=2;                continue;            }            ans[id]=1;            add_edge(u,v,id);            add_edge(v,u,id);        }        for(int k=i;k<=j;++k){            if(!pre[es[k].u])dfs(es[k].u,-1);        }        for(;i<=j;++i)            unite(es[i].u,es[i].v);    }    for(int i=0;i<m;++i){        if(ans[i]==2)puts("none");        else puts(ans[i]?"at least one":"any");    }    return 0;}/*    Jun.24.16    Tags:tree,MST,dsu,dfs,bridge    Submissions:2    Time 122ms    Memory 8100KB*/
0 0
原创粉丝点击