P4180 模板严格次小生成树[BJWC2010]

Posted edsheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4180 模板严格次小生成树[BJWC2010]相关的知识,希望对你有一定的参考价值。

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 技术分享图片 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input5 6 1 2 1 1 3 2 2 4 3 3 5 4 3 4 3 4 5 6

Sample Output11Hint

 

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

 

扪心自问,kruskal的本质是什么?

贪心

kruskal算法被证明,对于任何的u,v

有u到v之间边权最大值小于等于u到v未选入的边的边权

所以说,不严格次小生成树只要

遍历每条未选的边(u,v,d),用它替换u和v之间的最大边即可


现在我们的任务就是把不严格的不去掉

为什么它不严格?

因为

u到v之间边权最大值小于等于u到v未选入的边的边权

 

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;
#define ll long long
const int M = 100000 + 5;
const int ME = 6e5 + 10, P = 18;
long long inf = 1e14;
ll  mx[M][P+1], mi[M][P+1];
int dep[M], anc[M][P+1], fa[M], tot, h[M]; 
bool ban[ME], vis[M];
struct edge{int v, w, nxt;}G[M<<1];
struct node{int u, v, w, id;}g[ME];
void add(int u, int v, int w){
    G[++tot].v =v, G[tot].nxt = h[u], G[tot].w = w, h[u] = tot;
}
bool cmp(node A, node B){
    return A.w < B.w;
}
int find(int u){return u == fa[u] ? u : fa[u] = find(fa[u]);}

void dfs(int u, int f, int w){
    vis[u] = 1;
    dep[u] = dep[f] + 1;
    anc[u][0] = f, mx[u][0] = w, mi[u][0] = -inf;
    for(int p = 1; p <= P; p++){
        anc[u][p] = anc[anc[u][p-1]][p-1];
        mx[u][p] = max(mx[u][p-1], mx[anc[u][p-1]][p-1]);
        mi[u][p] = max(mi[u][p-1], mi[anc[u][p-1]][p-1]);
        if(mx[u][p-1] > mx[anc[u][p-1]][p-1])
            mi[u][p] = max(mi[u][p], mx[anc[u][p-1]][p-1]);
        else if(mx[u][p-1] < mx[anc[u][p-1]][p-1])
            mi[u][p] = max(mi[u][p], mx[u][p-1]);
    }
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        dfs(v, u, G[i].w);
    }
}
int getlca(int u, int v){
    if(dep[u] < dep[v]) swap(u, v);
    int t = dep[u] - dep[v];
    for(int p = 0; t; t>>=1, p++)
        if(t&1) u = anc[u][p];
    if(u == v) return u;
    for(int p = P; p >= 0; p--)
        if(anc[u][p] != anc[v][p])
            u = anc[u][p], v = anc[v][p];
    return anc[u][0];
}
ll get(int u, int v, int w){
    ll ret = -inf;
    for(int p = P; p >= 0; p--)
        if(dep[anc[u][p]] >= dep[v]){
            if(w == mx[u][p]) ret = max(ret, mi[u][p]);
            else ret = max(ret, mx[u][p]);
            u = anc[u][p];
        }
    return ret;
}
int main(){
    long long ans = 0, ret = inf;
    int n, m, u, v, w;
    scanf("%d%d", &n,&m);
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d", &u, &v, &w);
        g[i] = (node){u, v, w, i};
    }
    memset(mx[1], 0x8f, sizeof(mx[1]));
    memset(mi[1], 0x8f, sizeof(mi[1]));
    sort(g+1, g+1+m, cmp);
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1; i <= m; i++){
        int u = g[i].u, v = g[i].v;
        if(find(u) == find(v)) continue;
        fa[find(u)] = find(v);
        ans += 1LL*g[i].w;
        add(u, v, g[i].w), add(v, u, g[i].w);
        ban[i] = 1;
    }
    dfs(1, 0, 0);
    for(int i = 1; i <= n; i++) if(!vis[i])return !puts("orz");
    for(int i = 1; i <= m; i++){
        if(ban[i])continue;
        int u = g[i].u, v = g[i].v;
        int lca = getlca(u, v);
        ll s = get(u, lca, g[i].w);
        ll p = get(v, lca, g[i].w);
        ret = min(ret, 1LL*g[i].w - max(s, p));
    }
    printf("%lld
", ans+ret);
    
}

 

以上是关于P4180 模板严格次小生成树[BJWC2010]的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P4180 模板严格次小生成树[BJWC2010]次小生成树

P4180 模板严格次小生成树[BJWC2010]

P4180 模板严格次小生成树[BJWC2010]

P4180 模板严格次小生成树[BJWC2010]

luogu P4180 模板严格次小生成树[BJWC2010]

P4180 严格次小生成树[BJWC2010]