[Luogu] 次小生成树
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] 次小生成树的更多相关文章
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- [Luogu P4180][BJWC 2010]严格次小生成树
严格次小生成树,关键是“严格”,如果是不严格的其实只需要枚举每条不在最小生成树的边,如果得到边权和大于等于最小生成树的结束就行.原理就是因为Kruskal非常贪心,只要随便改一条边就能得到一个非严格的 ...
- luogu 4180 严格次小生成树
次小生成树,顾名思义和次短路的思路似乎很类似呀, 于是就先写了个kruskal(prim不会)跑出最小生成树,给所有路径打标记,再逐个跑最小生成树取大于最小生成树的最小值 50分 #include&l ...
- Luogu P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...
- 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...
- 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...
- 次小生成树Tree
次小生成树Treehttps://www.luogu.org/problemnew/show/P4180 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正 ...
- P4180-[BJWC2010]严格次小生成树【Kruskal,倍增】
正题 题目链接:https://www.luogu.com.cn/problem/P4180 题目大意 \(n\)个点\(m\)条边的一张无向图,求它的严格次小生成树. \(1\leq n\leq 1 ...
- HDU 4081Qin Shi Huang's National Road System(次小生成树)
题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...
随机推荐
- DecodingGenome(CodeForces-222E)【矩阵快速幂】
题目链接:https://vjudge.net/contest/333591#problem/L 题意:用m个字符构成长度为n的串,其中存在形如“ab”(表示a后不能放置b)的条件约束,问共有多少种构 ...
- linux fork进程请谨慎多个进程/线程共享一个 socket连接,会出现多个进程响应串联的情况。
昨天组内同学在使用php父子进程模式的时候遇到了一个比较诡异的问题 简单说来就是:因为fork,父子进程共享了一个redis连接.然后父子进程在发送了各自的redis请求分别获取到了对方的响应体. 复 ...
- 20190805-Python基础 第二章 列表和元组(2)列表
1. list函数,用于将字符串转换为列表 2. 基本的列表操作 修改列表 - 给元素赋值,使用索引表示法给特定的元素赋值,如x[1] = 2 删除元素 - 使用del语句即可 name1 = ['a ...
- Python【列表 字典 元组】
列表列表用中括号[ ]把各种数据框起来,每一个数据叫作“元素”.每个元素之间都要用英文逗号隔开各种类型的数据(整数/浮点数/字符串)————————————————————————————从列表提取单 ...
- Pygame小游戏练习二
@Python编程从入门到实践 Python项目练习 四.创建Ship类 建立ship.py,创建Ship类,管理飞船行为. # ship.py import pygame class Ship(): ...
- django 中静态文件项目加载问题
问题描述: django项目中创建了多个app后,每个app中都有对应的static静态文件.整个项目运行时这些静态文件的加载就是一个问题,因为整个项目我只参与了一部分,项目部署之类的并没有参与.我写 ...
- S02_CH13_ AXI_PWM 实验
S02_CH13_ AXI_PWM 实验 当学习了上一章的协议介绍内容后,开发基于这些协议的方案已经不是什么难事了,关键的一点就是从零到有的突破了.本章就以AXI-Lite总线实现8路LED自定义IP ...
- 牛客 133D 挑选队友 (分治FFT)
大意: $n$个人, 分别属于$m$个组, 要求选出$k$个人, 使得每组至少有一人, 求方案数. 显然答案为$\prod((1+x)^{a_i}-1)$的第$k$项系数, 分治$FFT$即可. #i ...
- [Tarjan系列] Tarjan算法求无向图的桥和割点
RobertTarjan真的是一个传说级的大人物. 他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决. 而且,Tarjan并不只发明了LCT,他对 ...
- Angular6如何引入jQuery-knob
Angular6如何引入jQuery-knob 1.概述 Angular6引入jQuery变得异常简单,请参考https://blog.csdn.net/qq_35321405/article/det ...