CodeForces Round #111 Div.2 problem D 160D

来源:互联网 发布:阿里云os是什么 编辑:程序博客网 时间:2024/06/05 14:53
/*题意:最小生成树and tarjan.给定一个简单无向连通图G(v,e),他的最小生成树为T(不一定唯一),对于图中的任意一条边,如果它不可能在T中,输出none,如果它一定在T中,输出any如果它可能在T中,输出at least one题解:只有有相同权值的边的时候才可能出现at least one的情况G的点集为N如果 e1,e2,e3...的权值相同,在N中以克鲁斯卡尔算法的方式加入所有边权小于e1的边(这个时候出现一些联通分量)把这些连通分量抽象成点(这一点并查集可以做到),那么出现一个新的图Y(一定无环),这Y中也以鲁斯卡尔算法的方式加入e1,e2, e3....(没加入的肯定是连通分量内部的边,必然为none),如果出现环(包括两条重边构成的环),那么这些加入的e必然是at least one,因为可以通过破环把其中之一剔除出最小生成树,其他的必然为any(这些是新图Y的割边)。*/#include <iostream>#include <algorithm>#include <map>#include <set>#include <cstdio>#include <vector>using namespace std;const int N=100009;struct Edge {    int u,v,w,ans,id;    bool operator<(const Edge &y) const    {        return this->w<y.w;    }}e[N];int n,m;bool cmp(Edge x,Edge y){    return x.id<y.id;}map<int,vector<int> > v,mark;map<int,int> vis,first;set<int> Set;int fa[N],tim;char res[][20]={"none","at least one","any"};int find(int x){    return fa[x]==x?x:fa[x]=find(fa[x]);}void tarjan(int x){    if(vis[x])return ;    vis[x]=first[x]=++tim;    for(int i=0;i<v[x].size();i++)    {        int y=v[x][i];        int Mark=mark[x][i];        if(Set.count(Mark))continue;//记录边是否访问过,漏掉重边构成的环        Set.insert(Mark);        tarjan(y);        if(vis[y]<vis[x])        {            vis[x]=vis[y];        }        if(vis[y]>first[x])//找到割边        {            e[Mark].ans=2;        }    }}int main() {    while(scanf("%d%d",&n,&m)!=EOF)    {        for(int i=0;i<=n;i++)fa[i]=i;        for(int i=0;i<m;i++)        {            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);            e[i].ans=0;            e[i].id=i;        }        sort(e,e+m);        for(int i=0;i<m;)        {            int s=i,x,y;            while(i<m&&e[i].w==e[s].w) i++;//挑出一段相同边权的边            v.clear();            vis.clear();            mark.clear();            Set.clear();            for(int j=s;j<i;j++)            {                x=find(e[j].u);                y=find(e[j].v);                if(x==y)continue;                e[j].ans=1;                v[x].push_back(y);                v[y].push_back(x);                mark[x].push_back(j);//记录两点间边的编号                mark[y].push_back(j);            }            for(map<int,vector<int> >::iterator it=v.begin();it!=v.end();it++)            {                tarjan(it->first);            }            for(int j=s;j<i;j++)            {                x=find(e[j].u);                y=find(e[j].v);                if(x==y)continue;                fa[x]=y;            }        }        sort(e,e+m,cmp);        for(int i=0;i<m;i++)        {            printf("%s\n",res[e[i].ans]);        }    }    return 0;}

原创粉丝点击