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. fiddler笔记:统计选项卡(Statistics)

    Request Count 选中的Session数. Bytes sent Http请求头和请求体中向外发送的字节总数. Bytes received HTTP请求头和请求体中接收到的所有字节数. R ...

  2. 第九章 MIZ702 ZYNQ片上ADC的使用

      9.0难度系数★☆☆☆☆☆☆ 9.1实验概述 这次借助zynq的内嵌的XADC来采集zynq内部的一些参数: •VCCINT:内部PL核心电压 •VCCAUX:辅助PL电压 •VREFP:XADC ...

  3. linux——环境变量

    环境变量 基本概念: 一般是指在操作系统中用来指定操纵系统运行环境的一些参数 当我们用动态库链接成功的时候,其实就是相关的环境变量帮助编译器进行查找. 环境变量通常具有某种特殊用途,还有在系统当中通常 ...

  4. poj 1753高斯

    和前面的开关问题差不多,就是要理解一下我们方程等号的右端代表的含义是什么.我们建立的方程是想让对位的位置变或者不变,然后生成增广矩阵的时候要多注意一点. ac代码: #include #include ...

  5. Oracle导入数据后中文乱码的解决方法

    解决方法: 方法一. 1.在运行命令行输入regedit,打开注册表编辑器 2.找到HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OraDb11g_home1 3.看N ...

  6. sqlserver跨库操作数据

    垮库只能读操作,写操作需要设置权限. USE [jdddb] GO /****** Object: StoredProcedure [dbo].[proc_LYOrderCancel] Script ...

  7. 关于Mybatis的几件小事(二)

    一.MyBatis缓存机制 1.简介 Mybatis包含了一个非常强大的查询缓存的特性,它可以非常方便地配置和定制. 缓存key极大提高查询效率 MyBatis系统中默认定义了两次缓存 默认情况下,只 ...

  8. JS ES6

    变量 let 块级作用域内有效 不能重复声明 不会预处理,不存在提升 var btns = document.getElementsByTagName('button'); for (let i = ...

  9. 3.MySQL的架构介绍

    MySQL简介: 高级MySQL:mysql 内核 sql优化工程师 mysql服务器的优化 各种参数常量设定 查询语句优化 主从复制 软硬件升级 容灾备份 sql编程 完整的mysql优化需要很深的 ...

  10. jq国际化i18n

    1.(main.js或)ajax.js引入文件 import './jquery.i18n.properties.min' //https://github.com/jquery-i18n-prope ...