码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-02-17 12:41:29      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:div   dfs   ace   bre   枚举   color   char   lin   维护   

题目链接

题意如题

做法

  • 先做一遍最小生成树
  • 枚举添加每一条非树边的情况,每一次构成一棵基环树,在环上找一条最长边(如果等于该非树边就用环上的严格次小边)
  • 倍增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; }

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

标签:div   dfs   ace   bre   枚举   color   char   lin   维护   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!