虽然中途写的时候有点波折,但是最后一发A,还是有点爽。

这虽然是个模板题,但还是涉及到许多知识的= =

首先我们求出一个最小生成树,并且求出其边权和\(ans\)。那么现在考虑加入其它的边,每次加入在树上就会形成一个环,这时因为是一个生成树,所以我们要删去一条边。很明显现在就要删去最小生成树上最大的边即可。

但这里有个问题,题目要求严格次小。假设现在加入的边权为\(w\),树上在环中的部分边权最大为\(maxw\),那么当\(w=maxw\)时,很显然我们要求一个次大边权\(maxw2\)来替换;否则直接把\(maxw\)替换就行了。

初步思路就是这样,接下来就是怎么去“替换”边,并且统计答案。

这里我们可以直接倍增地去做就好了(也有种\(O(n^2)\)的dfs算法,但倍增这么优秀,学它做什么。

设\(g[x][i][0/1]\)分别表示当前在\(x\)号结点,向上跳\(2^i\)个结点,中途经过边权的最大值以及次大值为多少。很显然最大值很容易求,即为

\[max(g[x][i-1][0],g[f[x][i-1]][i-1][0])
\]

求次大值的话就需要分情况讨论了,直接看代码部分吧,应该比较好理解(其实是我懒得打了

if(g[v][j - 1][0] == g[f[v][j - 1]][j - 1][0]) {
g[v][j][1] = max(g[v][j - 1][1], g[f[v][j - 1]][j - 1][1]) ;
} else if(g[v][j - 1][0] > g[f[v][j - 1]][j - 1][0]) {
g[v][j][1] = max(g[v][j - 1][1], g[f[v][j - 1]][j - 1][0]) ;
} else g[v][j][1] = max(g[f[v][j - 1]][j - 1][1], g[v][j - 1][0]) ;

那么之后对于每一条边的两个端点,我们就类似于找lca那样倍增地去找次大值就行了。注意这里次大值不能直接取\(g[x][i][1]\)的最大值,也应该像上面那样结合最大值来讨论一下。

详见代码吧,写得有点长(很多复制粘贴

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5, M = 3e5 + 5;
int n, m;
struct Edge{
int u, v, w;
bool operator < (const Edge &A)const{
return w < A.w;
}
}E[M];
struct edge{
int v, w, next;
}e[M];
int head[N], tot;
bool check[M] ;
void adde(int u, int v, int w) {
e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
}
int ff[N] ;
int find(int x) {
return ff[x] == x ? ff[x] : ff[x] = find(ff[x]) ;
}
ll ans ;
int f[N][20], deep[N];
ll g[N][20][2] ;
int Log2[N] ;
void dfs(int u, int fa) {
deep[u] = deep[fa] + 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if(v == fa) continue ;
f[v][0] = u;
g[v][0][0] = w;
g[v][0][1] = -1e9;
for(int j = 1; j <= 17; j++) f[v][j] = f[f[v][j - 1]][j - 1] ;
for(int j = 1; j <= 17; j++) {
g[v][j][0] = max(g[v][j - 1][0], g[f[v][j - 1]][j - 1][0]) ;
if(g[v][j - 1][0] == g[f[v][j - 1]][j - 1][0]) {
g[v][j][1] = max(g[v][j - 1][1], g[f[v][j - 1]][j - 1][1]) ;
} else if(g[v][j - 1][0] > g[f[v][j - 1]][j - 1][0]) {
g[v][j][1] = max(g[v][j - 1][1], g[f[v][j - 1]][j - 1][0]) ;
} else g[v][j][1] = max(g[f[v][j - 1]][j - 1][1], g[v][j - 1][0]) ;
}
dfs(v, u) ;
}
}
ll LCA(int x, int y) {
if(deep[x] < deep[y]) swap(x, y) ;
for(int i = 17; i >= 0; i--) {
if(deep[f[x][i]] >= deep[y]) x = f[x][i] ;
}
if(x == y) return x;
for(int i = 17; i >= 0; i--) {
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i] ;
}
return f[x][0] ;
}
ll getmx(int x, int y, int k) {
ll ans1 = 0, ans2 = 0, ans = 0;
int z = LCA(x, y) ;
int tx = x, ty = y;
for(int i = 17; i >= 0; i--)
if(deep[f[x][i]] >= deep[z]) ans1 = max(ans1, g[x][i][0]), x = f[x][i] ;
for(int i = 17; i >= 0; i--)
if(deep[f[y][i]] >= deep[z]) ans2 = max(ans2, g[y][i][0]), y = f[y][i] ;
if(!k) return max(ans1, ans2) ;
if(ans1 > ans2) {
x = tx;
for(int i = 17; i >= 0; i--)
if(deep[f[x][i]] >= deep[z]) ans = max(ans, g[x][i][1]), x = f[x][i] ;
ans = max(ans, ans2) ;
} else if(ans1 == ans2) {
x = tx, y = ty;
ans1 = 0, ans2 = 0;
for(int i = 17; i >= 0; i--)
if(deep[f[x][i]] >= deep[z]) ans1 = max(ans1, g[x][i][0]), x = f[x][i] ;
for(int i = 17; i >= 0; i--)
if(deep[f[y][i]] >= deep[z]) ans2 = max(ans2, g[y][i][0]), y = f[y][i] ;
ans = max(ans1, ans2) ;
} else {
y = ty;
for(int i = 17; i >= 0; i--)
if(deep[f[y][i]] >= deep[z]) ans2 = max(ans2, g[y][i][0]), y = f[y][i] ;
ans = max(ans, ans1) ;
}
return ans ;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0) ;
cin >> n >> m;
Log2[1] = 0;
for(int i = 2; i < N; i++) Log2[i] = Log2[i >> 1] + 1;
memset(head, -1, sizeof(head)) ;
for(int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
E[i] = Edge{u, v, w} ;
}
for(int i = 1; i <= n; i++) ff[i] = i;
sort(E + 1, E + m + 1) ;
for(int i = 1; i <= m; i++) {
int u = E[i].u, v = E[i].v, w = E[i].w;
int fx = find(u), fy = find(v) ;
if(fx != fy) {
check[i] = 1;
ans += w;
ff[fx] = fy;
adde(u, v, w); adde(v, u, w);
}
}
dfs(1, 0) ;
ll mn = 1e18;
for(int i = 1; i <= m; i++) {
if(check[i]) continue ;
int u = E[i].u, v = E[i].v, w = E[i].w;
int mx = getmx(u, v, 0) ;
if(mx == w) {
mx = getmx(u, v, 1) ;
mn = min(mn, ans - mx + (ll)w) ;
} else mn = min(mn, ans - mx + (ll)w) ;
}
cout << mn ;
return 0;
}

洛谷P4180 【模板】严格次小生成树[BJWC2010] 题解的更多相关文章

  1. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  2. 【洛谷P4180】严格次小生成树

    题目大意:给定一个 N 个顶点,M 条边的带权无向图,求该无向图的一个严格次小生成树. 引理:有至少一个严格次小生成树,和最小生成树之间只有一条边的差异. 题解: 通过引理可以想到一个暴力,即:先求出 ...

  3. 洛谷P4180 [Beijing2010组队]次小生成树Tree

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

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

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

  5. 洛谷P4180【Beijing2010组队】次小生成树Tree

    题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...

  6. 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】

    P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...

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

    P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...

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

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

  9. 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

随机推荐

  1. python发展

    python的创始人---吉多·范罗苏姆(Guido van Rossum)

  2. javascript 数组之间增加某个符合arr.join('、');

    var arr=["a","b","c"]; arr.join(',');//返回值是字符串:a,b,c

  3. 使用 Jest 和 Supertest 进行接口端点测试

    如何创建测试是一件困难的事.网络上有许多关于测试的文章,却从来不告诉你他们是如何开始创建测试的. 所以,今天我将分享我在实际工作中是如何从头开始创建测试的.希望能够对你提供一些灵感. 目录: 使用 E ...

  4. VisualStudio ------- vs发布软件

    上线的系统和自己做的系统有什么区别 上线的没有源代码,没有实体层,数据库访问层  业务逻辑层 只有表现层  而且也也没有    .cs 和 .psd   文件,这样就不能修改系统代码 他们都在 Web ...

  5. [转帖]【rinetd】CentOS7.x上轻量级TCP转发工具rinetd的安装配置

    [rinetd]CentOS7.x上轻量级TCP转发工具rinetd的安装配置 https://www.jianshu.com/p/2605d247b944 这一个写的更加全面了. 2019.07.0 ...

  6. Mysql 命令 load data infile 权限问题

    [1]Mysql命令load data infile 执行权限问题 工作中,经常会遇到往线上环境mysql数据库批量导入源数据的场景. 针对这个场景问题,mysql有一个很高效的命令:load dat ...

  7. 桥接(Bridge)模式

    桥接模式又称为柄体模式或接口模式.桥接模式的用意就是"将抽象化与实现化解耦,使得二者可以独立变化". 抽象化: 存在于多个实体中的共同的概念性联系,就是抽象化.作为一个过程,抽象化 ...

  8. Elasticsearch 记录

    查看集群运行状态 GET /_cat/health?v 响应 1573460861 16:27:41 my-application yellow 1 1 372 372 0 0 371 0 - 50. ...

  9. Java学习:数组的使用和注意事项

    数组 数组的概念:是一种容器,可以同时存放多个数据值 数组的特点: 数组是一种引用数据类型 数组当中的多个数据,类型必须统一 数组的长度在程序运行期间不可以改变 数组的初始化:在内存当中创建一个数组, ...

  10. 【mysql】新增列 时间戳

    参考地址:https://www.cnblogs.com/SZxiaochun/p/9299392.html ALTER TABLE worksheet_data_12 ), ADD COLUMN ` ...