1. 程式人生 > >Codeforces 160 D. Edges in MST

Codeforces 160 D. Edges in MST

air mat bool efi 允許 min 顏色 getchar() tchar


\(>Codeforces \space 160 D. Edges in MST<\)

題目大意 : 給出一張帶權無向圖,求對於這張圖上的每一條邊,其是必然存在於每一種最小生成樹中,還是至少存在於一種最小生成樹中,還是一定不會存在於最小生成樹中

$2 \leq n \leq 10^5, n - 1 \leq m \leq \min(10^5, \frac{n(n-1)}{2}) $

解題思路 :

考慮 \(kruskal\) 算法的本質,每次加進一條邊到生成樹中如果形成環就替換掉環上的一條最大的邊 (如果比它大)

考慮最小生成樹不同的原因本質就是替換掉的最大邊的邊權可以等於它,這樣最小生成樹的邊就會不同

那麽可以對於同種顏色的邊進行考慮,先求出小於該種邊權的邊都加進去後的森林

如果說一條邊會和這個森林形成環,說明環上的最大值小於它,那麽這條邊一定不存在於最小生成樹中

考慮剩下的一條邊如果要存在與所有最小生成樹中,那麽所有同權的邊都不能換掉它

也就是說單獨把存在與最小生成樹中的同權的邊組成一張無向圖,這條邊不在任意一個環上

也就是說,這條邊是一條割邊,所以可以通過一遍 \(Tarjan\) 確定一條在最小生成樹中的邊是否存在於所有最小生成樹中

註意 \(Tarjan\) 求割邊的算法不允許有重邊存在,所以在建圖之前要把重邊判掉,然後把由某條重邊組成的割邊日掉

考慮每一條邊只會被加進做 \(Tarjan\)

的圖中一次,所以復雜度是 \(O(mlogm)\)



/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define N (500005)
map<pair<int, int>, int> mp;
int Ans[N], fa[N], n, m; 
struct Point{ int x, y, z, id; } e[N];
inline bool cmp(Point A, Point B){ 
    return A.z < B.z; 
}
inline int ask(int x){ 
    return x == fa[x] ? x : fa[x] = ask(fa[x]); 
}
namespace Graph{
    int dfn[N], low[N], Index; 
    struct Edge{ int x, id; }; vector<Edge> g[N];
    map<int, int> mp; vector<int> s;
    inline void Clear(){
        for(int i = 0; i < s.size(); i++) 
            dfn[s[i]] = low[s[i]] = 0, g[s[i]].clear();
        s.clear(), mp.clear(), Index = 0;
    }
    inline void Add(int x, int y, int id){
        g[x].push_back((Edge){y, id});
        g[y].push_back((Edge){x, id});
        if(!mp[x]) s.push_back(x), mp[x] = 1;
        if(!mp[y]) s.push_back(y), mp[y] = 1;
    }
    inline void dfs(int u, int fa){
        dfn[u] = low[u] = ++Index;
        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i].x; 
            if(!dfn[v]){
                dfs(v, u), low[u] = Min(low[u], low[v]);
                if(low[v] > dfn[u]) Ans[g[u][i].id] = 2;
            }
            else if(v != fa) low[u] = Min(low[u], dfn[v]);
        }
    }
    inline void solve(){
        for(int i = 0; i < s.size(); i++) if(!dfn[s[i]]) dfs(s[i], 0);
    }
}
inline void solve(int l, int r){
    Graph::Clear(), mp.clear();
    for(int i = l; i <= r; i++){
        int p = ask(e[i].x), q = ask(e[i].y);
        if(p == q) Ans[e[i].id] = 1; 
        else{
            pair<int, int> now = make_pair(min(p, q), max(p, q));
            if(++mp[now] == 1) Graph::Add(p, q, e[i].id);
        }
    }
    Graph::solve();
    for(int i = l; i <= r; i++){
        int p = ask(e[i].x), q = ask(e[i].y);
        if(p == q) continue;
        if(mp[make_pair(min(p, q), max(p, q))] > 1) Ans[e[i].id] = 0;
    }
    for(int i = l; i <= r; i++){
        int p = ask(e[i].x), q = ask(e[i].y);
        if(p != q) fa[p] = q;
    }
}
int main(){
    read(n), read(m);
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1, x, y, z; i <= m; i++){
        read(x), read(y), read(z);
        e[i] = (Point){x, y, z, i};
    }
    sort(e + 1, e + m + 1, cmp), e[0].z = e[m+1].z = -1;
    for(int i = 1, l = 1; i <= m; i++){
        if(e[i].z != e[i-1].z) l = i;
        if(e[i].z != e[i+1].z) solve(l, i);
    }
    for(int i = 1; i <= m; i++){
        if(Ans[i] == 0) puts("at least one");
        if(Ans[i] == 1) puts("none");
        if(Ans[i] == 2) puts("any");
    }
    return 0;
}

Codeforces 160 D. Edges in MST