P4180 模板严格次小生成树[BJWC2010](严格次小生成树)
Posted blog-fgy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ", Ans); } int main() { Init(); Kruskal(); Solve(); return 0; }
以上是关于P4180 模板严格次小生成树[BJWC2010](严格次小生成树)的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P4180 模板严格次小生成树[BJWC2010]次小生成树