Codeforces 160 D. Edges in MST

Posted mangoyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 160 D. Edges in MST相关的知识,希望对你有一定的参考价值。


(>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的主要内容,如果未能解决你的问题,请参考以下文章

D. Weights Assignment For Tree Edges(11.27)

D. Weights Assignment For Tree Edges(11.27)

Codeforces Round #460 (Div. 2) D. Substring BFS拓扑排序dp

CodeForces - 1484F Useful Edges(最短路)

Codeforces 338 D. GCD Table

Codeforces Round #271 (Div. 2) D. Flowers (递推)