题目链接
思路:判断一条边是不是生成树的可能边,比如u->v那么只要知道u到v的简单路径中,有没有和u->v这条边的边权相等的,如果有,那么他们全都是可能边,这个做法可以尝试以下lca,不过笔者并不晓得lca路径上该怎么改。。。只能用另一种办法,把所有边权相等的边拿来一起考虑,如果一条边的两点已经在一个集合了,他们他们肯定是none,,接着就将这些边建图走tarjan来判断一下有没有桥,如果是桥的话就是any,否则都是least noe。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,m,cnt=0,dfn[maxn],low[maxn],father[maxn];
vector<pair<int,int>>g[maxn];
struct node{
int u,v,w,id,ans;
}s[maxn];
bool cmp(const node &a,const node &b)
{
return a.w<b.w;
}
bool cmp1(const node &a,const node &b)
{
return a.id<b.id;
}
int findfather(int x)
{
if(x==father[x]) return x;
int i=findfather(father[x]);
father[x]=i;
return i;
}
void tarjan(int x,int fa)//tarjan求桥
{
low[x]=dfn[x]=++cnt;
for(auto to:g[x])
{
if(fa==to.second) continue;//记住,这里防止走环的判断是根据边的编号而不是点
if(!dfn[to.first])
{
tarjan(to.first,to.second);
low[x]=min(low[x],low[to.first]);
if(low[to.first]>dfn[x]) s[to.second].ans=2;
}
else low[x]=min(low[x],low[to.first]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;++i) father[i]=i;
for(int i=1;i<=m;++i)
scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].w),s[i].id=i;
sort(s+1,s+1+m,cmp);
int i=1,j;
while(i<=m)
{
j=i;
while(j<=m&&s[i].w==s[j].w) j++;
for(int k=i;k<j;++k)//建边
{
int fa=findfather(s[k].u),fb=findfather(s[k].v);
if(fa==fb) continue;//已经在同一集合的两点肯定不符合要求
g[fa].push_back({fb,k});
g[fb].push_back({fa,k});
s[k].ans=1;
}
for(int k=i;k<j;++k)//求桥
{
int fa=findfather(s[k].u),fb=findfather(s[k].v);
if(fa==fb||dfn[fa]) continue;
tarjan(fa,-1);
}
for(int k=i;k<j;++k)//恢复原状
{
int fa=findfather(s[k].u),fb=findfather(s[k].v);
if(fa==fb) continue;
g[fa].clear();
g[fb].clear();
low[fa]=low[fb]=dfn[fa]=dfn[fb]=0;
father[fa]=fb;
}
i=j;
}
sort(s+1,s+1+m,cmp1);
for(int i=1;i<=m;++i)
if(s[i].ans==0) printf("none\n");
else if(s[i].ans==1) printf("at least one\n");
else printf("any\n");
}