最近发现,不写题解不长记性。
题意:给出一张带权无向图,然后询问该图的每条边进行询问,若这条边出现在该图的所有最小生成树中,输出any;若这条边可以出现在这张图的某几个最小生成树中,输出at least once;若这条边不会出现在这张图的任意一个最小生成树中,输出none。
解法:跟求最小生成树的方法类似,首先将所有边按照权值从小到大排序,一次取出所有边长相等的边,查询每条边的两个节点是否在同一集合中,若不在同一集合中,则在这两个集合间添加一条无向边,同时认为这些边有可能出现在该图的最小生成树中。再做tarjan找桥,找到桥将一定出现在该图的最小生成树中。然后将所有的边的两个端点合并到同一集合,在合并到同一集合的过程中,同时清除该在集合上的所有的边。
代码:

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 100010 using namespace std; struct Edge{ int from,to,dist,id; }a[maxn]; int first[maxn],v[maxn*2],next[maxn*2],id[maxn*2]; int ans[maxn],fa[maxn],pre[maxn],dfs_clock,e; int cmp(Edge a,Edge b){ return a.dist < b.dist; } void init(){ e = 0; memset(first,-1,sizeof(first)); } void add_edge(int a,int b,int ID){ v[e] = b; next[e] = first[a]; id[e] = ID; first[a] = e++; } int dfs(int u,int fa_id){ int lowu = pre[u] = ++dfs_clock; for(int i = first[u];i != -1;i = next[i]){ if(!pre[v[i]]){ int lowv = dfs(v[i],id[i]); lowu = min(lowu,lowv); if(lowv > pre[u]) ans[id[i]] = 1; }else if(pre[v[i]] < pre[u] && id[i] != fa_id){ lowu = min(lowu,pre[v[i]]); } } return lowu; } int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);} void join(int x,int y){ int fx = find(x); int fy = find(y); if(fx != fy){ e = 0; first[fx] = first[fy] = -1; pre[fx] = pre[fy] = 0; fa[fx] = fy; } } int main() { int n,m; scanf("%d%d",&n,&m); init(); for(int i = 1;i <= n;i++) fa[i] = i; dfs_clock = 0; for(int i = 0;i < m;i++){ scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].dist); a[i].id = i; } sort(a,a+m,cmp); memset(pre,0,sizeof(pre)); memset(ans,0,sizeof(ans)); for(int i = 0;i < m;i++){ int j = i+1; while(j < m && a[i].dist == a[j].dist) j++; for(int k = i;k < j;k++){ int fx = find(a[k].from); int fy = find(a[k].to); if(fx != fy){ add_edge(fx,fy,a[k].id); add_edge(fy,fx,a[k].id); ans[a[k].id] = 2; } } for(int k = i;k < j;k++){ int fx = find(a[k].from); int fy = find(a[k].to); if(fx != fy && !pre[fx]){ dfs(fx,-1); } } for(int k = i;k < j;k++){ join(a[k].from,a[k].to); } i = j - 1; } for(int i = 0;i < m;i++){ if(ans[i] == 0) printf("none "); else if(ans[i] == 1) printf("any "); else printf("at least one "); } return 0; }