CF160D

我们利用 $\text{kruskal}$ 的贪心思想去做这道题。

先考虑“一定不可能在任何 $\text{MST}$ 上”的情况。钦定用 $\text{kruskal}$ 形成的 $\text{MST}$ 为 $T$、当前考虑的边为 $e$、以及 $T$ 上在加入 $e$ 后与 $e$ 形成的简单环的边集为 $s$。那么不难发现,$s$ 中的所有边权都小于 $e$ 的边权,才会出现“一定不可能在任何 $\text{MST}$ 上”的情况。

具体的,我们可以分权值去考虑,每次在加入前先把所有同个权值的边放在 $\text{MST}$ 上进行查询,看看是否已经连通。若已经联通,那就必然满足上述条件,属于给出的第 $3$ 种情况。

再考虑剩下的边,依旧是分边权考虑。不妨把连通块都看成点——当我们加入一种边权的边时,会发现:一条边必定处于 $\text{MST}$ 中的充要条件是:它在图中是割边。$\text{Tarjan}$ 即可。

#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
const int N = 1e5 + 10;
struct Edge{int u, v, w, i;} g[N];
int n, m, tot, dfn[N], low[N], ans[N], fa[N];
vector<pair<int, int> > e[N];
int find(int x){return x == fa[x]? x : fa[x] = find(fa[x]);}
void dfs(int u, int id){
    low[u] = dfn[u] = ++tot;
    for(auto &x: e[u]){
        int v = x.first; if(x.second == id) continue;
        if(!dfn[v]) dfs(v, x.second), low[u] = min(low[u], low[v]);
        else low[u] = min(low[u], dfn[v]), ans[x.second] = 1;
    }
    ans[id] = (low[u] != dfn[u]);
}
bool cmp(Edge x, Edge y){return x.w < y.w;}
int main(){
    scanf("%d%d", &n, &m);
    FL(i, 1, n) fa[i] = i;
    FL(i, 1, m) scanf("%d%d%d", &g[i].u, &g[i].v, &g[i].w), g[i].i = i;
    sort(g + 1, g + m + 1, cmp);
    FL(i, 1, m){
        int j = i; while(j < m && g[j + 1].w == g[i].w) j++;
        FL(k, i, j){
            g[k].u = find(g[k].u), g[k].v = find(g[k].v);
            if(g[k].u == g[k].v){ans[g[k].i] = 2; continue;}
            e[g[k].u].emplace_back(make_pair(g[k].v, g[k].i));
            e[g[k].v].emplace_back(make_pair(g[k].u, g[k].i));
        }
        FL(k, i, j){
            if(!dfn[g[k].u]) dfs(g[k].u, 0);
            if(!dfn[g[k].v]) dfs(g[k].v, 0);
        }
        FL(k, i, j){
            dfn[g[k].u] = low[g[k].u] = dfn[g[k].v] = 0;
            low[g[k].v] = 0, fa[find(g[k].u)] = find(g[k].v);
            vector<pair<int, int> >().swap(e[find(g[k].u)]);
            vector<pair<int, int> >().swap(e[find(g[k].v)]);
        }
        i = j;
    }
    FL(i, 1, m) printf(!ans[i]? "any\n" : (ans[i] < 2? "at least one\n" : "none\n")); 
    return 0;
}
posted @ 2023-08-10 19:03  徐子洋  阅读(4)  评论(0编辑  收藏  举报  来源