https://www.luogu.org/problemnew/show/P4180#sub

严格次小生成树,即不等于最小生成树中的边权之和最小的生成树

首先求出最小生成树,然后枚举所有不在最小生成树里的边,找出最小增量,

如果将一条不在最小生成树里的边加入生成树,那么就会形成环

如图,绿色为最小生成树,如果将红色边加入,就在紫色区域构成了环

那么现在增量就是用红色边的边权 - 紫色区域内最大的绿色边的边权
这里红色边的边权一定大于等于紫色区域内最大的绿色边的边权(由最小生

成树的构成可知),如果红色边的边权 = 紫色区域内最大的绿色边的边权

那么紫色区域就要取次大值(因为要求严格次小)

套路:将这个环分成 lca (红色边的u,v的lca) 到 u 和 lca 到 v 两条路径

倍增最大值和次大值即可

Answer = 最小生成树 + 最小增量

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std;
const int N = 1e5 + ; #define gc getchar() int n, m, now = ;
struct Node {
int u, v, w, is_in;
bool operator <(const Node a)const {
return w < a.w;
}
} E[N * ];
struct Node_2{int u, v, w, nxt;} G[(N * ) << ];
int fa[N][], Max[N][], Tmax[N][], deep[N], head[N], father[N];
int Mi[]; #define LL long long
LL Answer; int Min = 1e9; inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' || c >= '') x = x * + c - '', c = gc;
return x;
} void Add(int u, int v, int w) {G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++;}
int Getfa(int x) {return father[x] == x ? x : father[x] = Getfa(father[x]);} void Mst() {
int js();
for(int i = ; js != n - ; i ++) {
int u = E[i].u, v = E[i].v, fu = Getfa(u), fv = Getfa(v);
if(fu != fv) {
father[fu] = fv;
js ++;
E[i].is_in = ;
Answer += (LL)E[i].w;
Add(E[i].u, E[i].v, E[i].w);
Add(E[i].v, E[i].u, E[i].w);
}
}
} void Dfs(int x, int f_, int dep) {
deep[x] = dep;
for(int i = ; ; i ++) {
if(deep[x] - Mi[i] < ) break;
fa[x][i] = fa[fa[x][i - ]][i - ];
Max[x][i] = max(Max[x][i - ], Max[fa[x][i - ]][i - ]);
if(Max[x][i - ] == Max[fa[x][i - ]][i - ])
Tmax[x][i] = max(Tmax[x][i - ], Tmax[fa[x][i - ]][i - ]);
else
Tmax[x][i] = max(min(Max[x][i - ], Max[fa[x][i - ]][i - ]),
max(Tmax[x][i - ], Tmax[fa[x][i - ]][i - ]));
}
for(int i = head[x]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != f_) {fa[v][] = x; Max[v][] = G[i].w; Tmax[v][] = -; Dfs(v, x, dep + );}
}
} int Lca(int x, int y) {
if(deep[x] < deep[y]) swap(x, y);
int k = deep[x] - deep[y];
for(int i = ; i <= ; i ++)
if(k >> i & ) x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i --)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][];
} void Work(int s, int t, int w_) {
int m1 = , m2 = , k = deep[s] - deep[t];
for(int i = ; i <= ; i ++) {
if(k >> i & ) {
m2 = max(m2, Tmax[s][i]);
if(Max[s][i] > m1) {m2 = max(m2, m1); m1 = Max[s][i];}
}
}
if(m1 == w_) Min = min(Min, w_ - m2);
else Min = min(Min, w_ - m1);
} int main() {
n = read(); m = read();
for(int i = ; i <= n; i ++) head[i] = -, father[i] = i;
Mi[] = ;
for(int i = ; i <= ; i ++) Mi[i] = Mi[i - ] * ;
for(int i = ; i <= m; i ++) {E[i].u = read(), E[i].v = read(), E[i].w = read();}
sort(E + , E + m + );
Mst();
Dfs(, , );
for(int i = ; i <= m; i ++) {
if(!E[i].is_in) {
int u = E[i].u, v = E[i].v;
int L = Lca(u, v);
Work(u, L, E[i].w);
Work(v, L, E[i].w);
}
}
cout << Answer + Min;
return ;
}

树剖版,cogs AC,luogu 80

线段树维护区间最大和严格次大

/*
次小生成树的链剖实现
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std;
const int N = 1e5 + ; #define gc getchar()
#define LL long long int n, m, now = , Tim, Min = (int)1e9, Max1, Max2;
int head[N], deep[N], top[N], fa[N], tree[N], bef[N], size[N], son[N], dad[N], data[N];
int Max[N << ], Tmax[N << ];
struct Node {
int u, v, w, is_in;
bool operator <(const Node a) const {return w < a.w;}
}E[N << ];
struct Node_2{int u, v, w, nxt;} G[N << ];
LL Answer; inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' || c >= '') x = x * + c - '', c = gc;
return x;
} void Add(int u, int v, int w) {G[now].u = u; G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++;}
int Getfa(int x) {return dad[x] == x ? x : dad[x] = Getfa(dad[x]);} void Dfs_find_son(int u, int f_, int dep) {
fa[u] = f_;
deep[u] = dep;
size[u] = ;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != f_) {
data[v] = G[i].w;
Dfs_find_son(v, u, dep + );
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
}
} void Dfs_un(int u, int tp) {
top[u] = tp;
tree[u] = ++ Tim;
bef[Tim] = u;
if(!son[u]) return ;
Dfs_un(son[u], tp);
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u] && v != son[u]) Dfs_un(v, v);
}
} void Mst() {
int js();
for(int i = ; js != n - ; i ++) {
int u = E[i].u, v = E[i].v, fu = Getfa(u), fv = Getfa(v);
if(fu != fv) {
dad[fu] = fv; js ++; E[i].is_in = ; Answer += (LL)E[i].w;
Add(E[i].u, E[i].v, E[i].w); Add(E[i].v, E[i].u, E[i].w);
}
}
} #define lson jd << 1
#define rson jd << 1 | 1 void Push_up(int jd) {
if(Max[lson] == Max[rson]) {
Max[jd] = Max[lson];
Tmax[jd] = max(Tmax[lson], Tmax[rson]);
} else {
Max[jd] = max(Max[lson], Max[rson]);
Tmax[jd] = max(min(Max[lson], Max[rson]), max(Tmax[lson], Tmax[rson]));
}
} void Build_tree(int l, int r, int jd) {
if(l == r) {
Max[jd] = data[bef[l]];
Tmax[jd] = -;
return ;
}
int mid = (l + r) >> ;
Build_tree(l, mid, lson);
Build_tree(mid + , r, rson);
Push_up(jd);
} int Lca(int x, int y) {
int tp1 = top[x], tp2 = top[y];
while(tp1 != tp2) {
if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);
x = fa[tp1];
tp1 = top[x];
}
return deep[x] < deep[y] ? x : y;
} void Sec_G(int l, int r, int jd, int x, int y) {
if(x <= l && r <= y) {
if(Max[jd] > Max1) {Max2 = max(Max1, Tmax[jd]); Max1 = Max[jd];}
else if(Max[jd] == Max1) Max2 = max(Max2, Tmax[jd]);
else Max2 = max(Max2, Max[jd]);
return ;
}
int mid = (l + r) >> ;
if(x <= mid) Sec_G(l, mid, lson, x, y);
if(y > mid) Sec_G(mid + , r, rson, x, y);
} void Sec_G_imp(int x, int y, int w_) {
int tp1 = top[x], tp2 = top[y], M1 = , M2 = ;
while(tp1 != tp2) {
if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);
Max1 = , Max2 = ;
Sec_G(, n, , tree[tp1], tree[x]);
if(Max1 > M1) {M2 = max(M1, Max2), M1 = Max1;}
else if(Max1 == M1) M2 = max(M2, Max2);
else M2 = max(M2, Max1);
x = fa[tp1]; tp1 = top[x];
}
if(x == y) return ;
if(deep[x] < deep[y]) swap(x, y);
Max1 = , Max2 = ;
Sec_G(, n, , tree[y] + , tree[x]);
if(Max1 > M1) {M2 = max(M1, Max2), M1 = Max1;}
else if(Max1 == M1) M2 = max(M2, Max2);
else M2 = max(M2, Max1);
if(M1 == w_) Min = min(Min, w_ - M2);
else Min = min(Min, w_ - M1);
} int main() {
n = read(), m = read();
for(int i = ; i <= n; i ++) dad[i] = i, head[i] = -;
for(int i = ; i <= m; i ++) {E[i].u = read(), E[i].v = read(), E[i].w = read();}
sort(E + , E + m + );
Mst();
Dfs_find_son(, , );
Dfs_un(, );
Build_tree(, n, );
for(int i = ; i <= m; i ++){
if(!E[i].is_in) {
int u = E[i].u, v = E[i].v;
Sec_G_imp(u, v, E[i].w);
}
}
std:: cout << Answer + Min;
return ;
}

[Luogu] 次小生成树的更多相关文章

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

    题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...

  2. [Luogu P4180][BJWC 2010]严格次小生成树

    严格次小生成树,关键是“严格”,如果是不严格的其实只需要枚举每条不在最小生成树的边,如果得到边权和大于等于最小生成树的结束就行.原理就是因为Kruskal非常贪心,只要随便改一条边就能得到一个非严格的 ...

  3. luogu 4180 严格次小生成树

    次小生成树,顾名思义和次短路的思路似乎很类似呀, 于是就先写了个kruskal(prim不会)跑出最小生成树,给所有路径打标记,再逐个跑最小生成树取大于最小生成树的最小值 50分 #include&l ...

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

    P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...

  5. 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

    非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...

  6. 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)

    洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...

  7. 次小生成树Tree

    次小生成树Treehttps://www.luogu.org/problemnew/show/P4180 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正 ...

  8. P4180-[BJWC2010]严格次小生成树【Kruskal,倍增】

    正题 题目链接:https://www.luogu.com.cn/problem/P4180 题目大意 \(n\)个点\(m\)条边的一张无向图,求它的严格次小生成树. \(1\leq n\leq 1 ...

  9. HDU 4081Qin Shi Huang's National Road System(次小生成树)

    题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...

随机推荐

  1. java web开发环境设置

    Mapped Statements collection does not contain value for后面是什么类什么方法之类的问题: 除了"https://changbl.itey ...

  2. 落网数据库简单查询接口 caddy+php7+mongodb

    落网数据库简单查询接口 一个简单的DEMO,使用了caddy + php7 + mongodb 数据库&接口设计 来自 https://github.com/Aedron/Luoo.spide ...

  3. 内存溢出,内存泄漏,CPU溢出区别

    内存溢出 out of memory,就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用 ...

  4. ThreadLocal使用场景,原理

    ThreadLocal 1. 先说下 ThreadLocal不能解决多线程间共享数据,他是一个隔离多线程间共享数据的好帮手 2. ThreadLocal是本地线程共享数据 3. 他是以空间换时间 sy ...

  5. k8s之自定义指标API部署prometheus

    1.自定义指标-prometheus node_exporter是agent;PromQL相当于sql语句来查询数据; k8s-prometheus-adapter:prometheus是不能直接解析 ...

  6. luogu P4762 [CERC2014]Virus synthesis (回文自动机)

    大意: 初始有一个空串, 操作(1)在开头或末尾添加一个字符. 操作(2)在开头或末尾添加该串的逆串. 求得到串$S$所需最少操作数. 显然最后一定是由某个偶回文通过添加字符得到的, 那么只需要求出所 ...

  7. MyBatis MyBatis Generator入门

    一.MGB功能简介 MyBatis Generator是一个代码生成工具. MBG是如何运行的呢?它会检查所连接到的数据库的一个或者多个table,然后生成可用来访问这些table的构建(Java代码 ...

  8. hdu 2680 Dijstra

    Choose the best route Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  9. ADO连接达梦7数据库,利用OLEDB建立连接

    达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且 ...

  10. Qt使用自带的windeployqt 查找生成exe 必需的库文件

    集成开发环境 QtCreator 目前生成图形界面程序 exe 大致可以分为两类:Qt Widgets Application  和 Qt Quick Application.下面分别介绍这两类exe ...