P4180 【模板】严格次小生成树[BJWC2010](严格次小生成树)

题目链接

题意如题

做法

  • 先做一遍最小生成树
  • 枚举添加每一条非树边的情况,每一次构成一棵基环树,在环上找一条最长边(如果等于该非树边就用环上的严格次小边)
  • 倍增LCA,倍增预处理的时候顺便维护严格次大值和最大值(注意细节)
  • (如果是非严格次小生成树则只需要维护最大值即可)

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define reg register
#define LL long long
using namespace std;

const int maxN = 100005, maxM = 300005;

inline int read() {
    int x = 0; char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x;
}
int N, M;
LL Ans = 1e18, MST;

struct Edge {
    int dis, nxt, to;
}e[maxM << 1]; int cnte = 1, head[maxN];
inline void add_Edge(int i, int j, int k) {
    e[++cnte].dis = k, e[cnte].nxt = head[i], e[cnte].to = j, head[i] = cnte;
}

int fa[maxN];
int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
void merge(int x, int y) {fa[find(x)] = find(y);}

struct EE {
    int u, v, w;
    bool is;
}E[maxM];
bool cmp(EE x, EE y) {
    return x.w < y.w;
}
void Init() {
    N = read(), M = read();
    for(reg int i = 1; i <= M; ++i) {
        E[i].u = read(), E[i].v = read(), E[i].w = read();
    }
}
void Kruskal() {
    int cnt = 0;
    sort(E + 1, E + M + 1, cmp);
    for(int i = 1; i <= N; ++i) fa[i] = i;
    for(reg int i = 1; i <= M; ++i) {
        reg int u = E[i].u, v = E[i].v, w = E[i].w;
        if(u == v) {
            E[i].is = true;
            continue;
        }
        if(find(u) != find(v)) {
            add_Edge(u, v, w), add_Edge(v, u, w);
            merge(u, v), ++cnt,
            E[i].is = true,
            MST += w;
        }
        if(cnt == N - 1) break;
    }
}
int g[maxN][30], dep[maxN], f[maxN][30], h[maxN][30];//g数组是最大值,h数组是严格次大值
void dfs(int u, int father) {
    for(reg int v, i = head[u]; i; i = e[i].nxt) {
        if((v = e[i].to) == father) continue;
        dep[v] = dep[u] + 1,
        f[v][0] = u, h[v][0] = g[v][0] = e[i].dis,
        dfs(v, u);
    }
}
void Pre() {
    memset(h, -0x7f, sizeof(h)),
    memset(g, -0x7f, sizeof(g));
    dep[1] = 1, f[1][0] = 1;
    dfs(1, 0);
    for(int i = 1; i <= 21; ++i) {
        for(int u = 1; u <= N; ++u) {
            f[u][i] = f[f[u][i - 1]][i - 1],       //注意一下处理
            g[u][i] = max(g[u][i - 1], g[f[u][i - 1]][i - 1]),
            h[u][i] = min(g[u][i - 1], g[f[u][i - 1]][i - 1]);
            if(i == 1) continue;
            if(g[u][i - 1] == g[f[u][i - 1]][i - 1]) {
                h[u][i] = max(h[u][i - 1], h[f[u][i - 1]][i - 1]);
            }
            else {
                h[u][i] = max(h[u][i], h[u][i - 1]),
                h[u][i] = max(h[u][i], h[f[u][i - 1]][i - 1]);
            }
        }
    }
}
int LCA(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 20; i >= 0; --i) if(dep[f[x][i]] >= dep[y]) x = f[x][i];
    if(x == y) return x;
    for(int i = 20; i >= 0; --i) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
int Query(int down, int up, int now) {
    int ret = -1e18;
    for(int i = 20; i >= 0; --i) {
        if(dep[f[down][i]] >= dep[up]) {
            if(now != g[down][i]) ret = max(ret, g[down][i]);
            else ret = max(ret, h[down][i]);
            down = f[down][i];
        }
    }
    return ret;
}
void Solve() {
    Pre();
    for(int i = 1; i <= M; ++i) {
        if(E[i].is) continue;
        int x = E[i].u, y = E[i].v;
        int lca = LCA(x, y), k;
        k = Query(x, lca, E[i].w), k = max(k, Query(y, lca, E[i].w));
        if(k == E[i].w) continue;
        Ans = min(Ans, MST + (E[i].w - k));
    }
    printf("%lld\n", Ans);
}
int main() {
    Init();
    Kruskal();
    Solve();
    return 0;
}

原文地址:https://www.cnblogs.com/blog-fgy/p/12320925.html

时间: 2024-10-10 01:04:43

P4180 【模板】严格次小生成树[BJWC2010](严格次小生成树)的相关文章

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

严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点的路径上的最长边,如果最长边等于枚举到的边的边权,那么选次长边(没有次长边的话直接跳过),然后在最小生成树的权值上减去路径上最/次长边,加上当前枚举的边的边权 因为如果加入枚举的边的,那么就形成了一个环,需要断开一条边 注意一开始单点次小值赋为0 #include<iostream> #inclu

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

P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了.小\(P\)说,让小\(C\)求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是\(E_M\),严格次小生成树选择的边集是\(E_S\),那么需要满足:(\(value(e)\)表示边\(e\)的权值)\

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

传送门 次小生成树 那肯定是最小生成树上改一条边(改两条肯定不如只改其中一条小) 那就枚举所有不在最小生成树上的边 考虑如果把此边加入,另一边删除后的情况 考虑要删哪条边后才能保持树的形态,并且总长最小 加入一条边后树就会出现一个环 那么删掉的边要在加入的边连接的两点间的路径上 并且删去的边要尽量大 那就可以用LCA来求出树上两点间路径上的最长边 但是现在还有一个问题,可能删去的边和加入的边一样长 所以还要维护一下次长的边 次长边维护也不难,具体看代码 #include<iostream> #

P4180 严格次小生成树[BJWC2010]

题目链接 https://www.luogu.org/problemnew/show/P4180 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) \sum_{e \in E_M}value(e)<\sum_{e

P4180 严格次小生成树[BJWC2010] Kruskal,倍增

题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可以由最小生成树删一条边再加一条边得到.我们枚举加上去的这一条边,加上去以后原\(mst\)会成为一个基环树,想让它次小就在这个环里找一条最长的边(不包含新加进去的)删掉就好.放在树上来讲,就是找到\(u\)到\(v\)路径上的最大值.这样我们就有了非严格次小生成树. 严格要怎么处理?我们需要排除新加

【BJWC2010】次小生成树

题目链接:https://www.luogu.com.cn/problem/P4180 题目大意:给定一张含有 \(m\) 条边的无向带权图 , 求出这张图中边权之和严格大于最小生成树的次小生成树的边权之和 solution 笔者太鸽了 , 一连咕了三天 , 因此来补一下前两天的锅 这道题的思路很显然 , 先求出这张图的最小生成树 , 记它的边权之和为\(sum\) , 再考虑剩下的 \(m - n + 1\) 条边 , 如果把第 \(i\) 条, 分别连接\(a_i , b_i\), 权值为\

严格次小生成树[BJWC2010]

题目 维护环内最大值与严格次大值 与未放入最小生成树的边枚举加入 #include<bits/stdc++.h> #define re return #define dec(i,l,r) for(ll i=l;i>=r;--i) #define inc(i,l,r) for(ll i=l;i<=r;++i) typedef long long ll; using namespace std; template<typename T>inline void rd(T&am

bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 因为严格,所以要记录到 LCA 的一个次小值: 很快写好,然后改掉一堆错误后终于过了样例!然而交上去1WA: 又改了半天,还是WA,于是放弃,抄题解好久... 然而就在我调了一个小时终于锁定错误就在那个子函数里的时候才突然看到了自己的明显惊天大错误是怎么回事??!!!稍微改了一下下就完美AC... 不过还有点收获,把求各种层次的 f 放在 dfs 函数里会比单独拿出来再求一遍快 10

POJ_1679_The Unique MST(次小生成树模板)

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 23942   Accepted: 8492 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire