题意
给你一张联通无向图,没有自环和重边。
问每一条边是:
- 在所有MST中(输出"any");
- 在至少一个MST中(输出"at least one");
- 不在任何MST中(输出"none")。
思路
利用kruskal的思想及证明(感性,严谨证明可看OI wiki),对于边权小的边应先加入MST中,因为如果这不是最优的,那么必然在原图中有另一条更短路连接这两个联通块,那么此边就不是最短边了。
于是就可以对不同的边权值分层。
然后对于同一层的边有三种情况:
- 两端连接同一联通块,代表这条边不会出现在MST中。
- 将当层的边加入图中后它是桥(割边),代表这条边一定出现在所有MST中。
- 不是上面两种情况,说明当层的所有边加入图中后组成了一个环,而环上的边是可以替代的,于是此状态代表出现在至少一个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;
}
}
}