P4180 严格次小生成树[BJWC2010] Kruskal,倍增
题意就是要求一个图的严格次小生成树。以前被题面吓到了没敢做,写了一下发现并不难。
既然要考虑次小我们就先考虑最小。可以感性理解到一定有一种次小生成树,可以由最小生成树删一条边再加一条边得到。我们枚举加上去的这一条边,加上去以后原\(mst\)会成为一个基环树,想让它次小就在这个环里找一条最长的边(不包含新加进去的)删掉就好。放在树上来讲,就是找到\(u\)到\(v\)路径上的最大值。这样我们就有了非严格次小生成树。
严格要怎么处理?我们需要排除新加上的边和\(u\)到\(v\)路径最长边相等的情况。仔细思考会发现可以再倍增维护一个次大长度,如果最大长度严格小于新加上边的长度就选用最大,否则就用次大。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100000 + 5;
const int M = 300000 + 5;
const int INF = 0x7fffffff;
const LL INFF = 0x7fffffffffffffff;
struct Graph {
int cnt, head[N];
struct Edge {int nxt, to, w;}e[N << 1];
void clear () {
cnt = -1;
memset (head, -1, sizeof (head));
}
void add_len (int u, int v, int w) {
e[++cnt] = (Edge) {head[u], v, w}; head[u] = cnt;
e[++cnt] = (Edge) {head[v], u, w}; head[v] = cnt;
}
int deep[N], pre[N][20], w1st[N][20], w2nd[N][20];
void dfs (int u, int fa) {
deep[u] = deep[fa] + 1;
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
dfs (v, u);
pre[v][0] = u;
w2nd[v][0] = -INF;
w1st[v][0] = e[i].w;
}
}
}
void build (int u) {
for (int i = 1; (1 << i) <= deep[u]; ++i) {
pre[u][i] = pre[pre[u][i - 1]][i - 1];
w1st[u][i] = max (w1st[u][i - 1], w1st[pre[u][i - 1]][i - 1]);
w2nd[u][i] = max (w2nd[u][i - 1], w2nd[pre[u][i - 1]][i - 1]);
if (w1st[u][i - 1] < w1st[pre[u][i - 1]][i - 1]) {
w2nd[u][i] = max (w2nd[u][i], w1st[u][i - 1]);
}
if (w1st[u][i - 1] > w1st[pre[u][i - 1]][i - 1]) {
w2nd[u][i] = max (w2nd[u][i], w1st[pre[u][i - 1]][i - 1]);
}
}
for (int i = head[u]; ~i; i = e[i].nxt) {
if (e[i].to != pre[u][0]) build (e[i].to);
}
}
int lca (int u, int v) {
if (deep[u] < deep[v]) swap (u, v);
for (int i = 19; i >= 0; --i) {
if (deep[u] - deep[v] >= (1 << i)) {
u = pre[u][i];
}
}
if (u == v) return u;
for (int i = 19; i >= 0; --i) {
if (pre[u][i] != pre[v][i]) {
u = pre[u][i];
v = pre[v][i];
}
}
return pre[u][0];
}
int query (int u, int v, int w) {
//求u到v之间严格小于w的最大的值
int ans = -INF;
for (int i = 19; i >= 0; --i) {
if (deep[v] - deep[u] >= (1 << i)) {
if (w1st[v][i] < w) {
ans = max (ans, w1st[v][i]);
} else {
ans = max (ans, w2nd[v][i]);
}
v = pre[v][i];
}
}
return ans;
}
}G;
struct Len {
int u, v, w;
bool operator < (Len rhs) const {
return w < rhs.w;
}
Len () {}
Len (int u, int v, int w) : u(u), v(v), w(w) {}
}arr[M];
int n, m, Set[N], in_mst[M];
int find (int x) {
return x == Set[x] ? x : (Set[x] = find (Set[x]));
}
int main () {
G.clear ();
cin >> n >> m;
for (int i = 0; i < m; ++i) {
static int u, v, w;
cin >> u >> v >> w;
arr[i] = Len (u, v, w);
}
sort (arr, arr + m);
for (int i = 0; i <= n; ++i) Set[i] = i;
LL mstw = 0;
for (int i = 0; i < m; ++i) {
int u = arr[i].u;
int v = arr[i].v;
int w = arr[i].w;
if (find (u) != find (v)) {
mstw += w;
in_mst[i] = true;
G.add_len (u, v, w);
Set[find (u)] = find (v);
}
}
G.w1st[1][0] = -INF;
G.dfs (1, 0);
G.build (1);
LL ans = INFF;
for (int i = 0; i < m; ++i) {
if (!in_mst[i]) {
int u = arr[i].u;
int v = arr[i].v;
int w = arr[i].w;
int _lca = G.lca (u, v);
int maxu = G.query (_lca, u, w);
int maxv = G.query (_lca, v, w);
ans = min (ans, mstw + w - max (maxu, maxv));
}
}
cout << ans << endl;
}
P4180 严格次小生成树[BJWC2010] Kruskal,倍增的更多相关文章
- 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)
题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- P4180-[BJWC2010]严格次小生成树【Kruskal,倍增】
正题 题目链接:https://www.luogu.com.cn/problem/P4180 题目大意 \(n\)个点\(m\)条边的一张无向图,求它的严格次小生成树. \(1\leq n\leq 1 ...
- Luogu P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...
- P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...
- 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】
P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...
- 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...
- 严格次小生成树[BJWC2010] (树链剖分,倍增,最小生成树)
题目链接 Solution 有几点关键,首先,可以证明次小生成树一定是由最小生成树改变一条边而转化来. 所以需要枚举所有非最小生成树的边\((u,v)\).并且找到 \(u\) 到 \(v\) 的边中 ...
随机推荐
- K邻近回归算法
代码: # -*- coding: utf-8 -*- """ Created on Fri Jul 13 10:40:22 2018 @author: zhen &qu ...
- 简单易懂的单元测试框架-gtest(一)
简介 gtest是google开源的一个单元测试框架,以其简单易学的特点被广泛使用.该框架以第三方库的方式插入被测代码中.同其他单元测试框架相似,gtest也通过制作测试样例来进行代码测试.同 ...
- spring笔记----看书笔记
上周末看了一章以前javaee轻量级的书spring部分,简单做了一些笔记 // ApplicationContext ac=new ClassPathXmlApplicationContext(&q ...
- 简单介绍python的双向队列
介绍 大家都知道利用 .append 和 .pop 方法,我们可以把列表当作栈或者队列来用(比如,把 append 和 pop(0) 合起来用,就能模拟栈的“先进先出”的特点).但是删除列表的第一个元 ...
- Python 之网络式编程
一 客户端/服务器架构 即C/S架构,包括 1.硬件C/S架构(打印机) 2.软件B/S架构(web服务) C/S架构与Socket的关系: 我们学习Socket就是为了完成C/S的开发 二 OSI七 ...
- 在centos中搭建基于nginx的apt源服务器,整合yum源和apt源在一台服务器
1.首先关闭防护墙或者设置规则通过且关闭selinux 2.nginx-1.14.2版本(编译安装)-自定义安装路径 3.开启nginx目录浏览 以上步骤请参考前文:https://www.cnblo ...
- JVM内存结构简单认知
关于JVM的面试传送门:https://blog.csdn.net/shengmingqijiquan/article/details/77508471 JVM内存结构主要划分为:堆,jvm栈,本地方 ...
- 利用gulp,当引入文件改动时,版本号自动更新~
gulp自动更新版本号 安装依赖 yarn add gulp-rev yarn add gulp-rev-collector 本次依赖的版本号为: "gulp": "^3 ...
- 10分钟学会在Ubuntu 18.04 LTS上安装NFS服务器和客户端
https://www.linuxidc.com/Linux/2018-11/155331.htm
- Git操作记录
记录一些用过的操作 增加远程推送分支 git remote add orgin http://xxxxx.git 直接新建本地分支,将远程分支提取出来. git checkout -t origin/ ...