题目链接\(Click\) \(Here\)

题意就是要求一个图的严格次小生成树。以前被题面吓到了没敢做,写了一下发现并不难。

既然要考虑次小我们就先考虑最小。可以感性理解到一定有一种次小生成树,可以由最小生成树删一条边再加一条边得到。我们枚举加上去的这一条边,加上去以后原\(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,倍增的更多相关文章

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

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

  2. 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)

    题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...

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

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

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

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

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

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

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

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

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

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

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

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

  9. 严格次小生成树[BJWC2010] (树链剖分,倍增,最小生成树)

    题目链接 Solution 有几点关键,首先,可以证明次小生成树一定是由最小生成树改变一条边而转化来. 所以需要枚举所有非最小生成树的边\((u,v)\).并且找到 \(u\) 到 \(v\) 的边中 ...

随机推荐

  1. adb 查看 android手机的CPU架构

    adb shell cat  /proc/cpuinfo 当然要下载adb并配置好环境变量

  2. JMeter接口测试实战-动态数据验证

    JMeter接口测试实战-动态数据验证 说到验证就不得不说断言, 先来看下JMeter官方给出断言(Assertion)的定义, 用于检查测试中得到的响应数据等是否符合预期,用以保证测试过程中的数据交 ...

  3. 安装Docker时错误提示 "could not change group /var/run/docker.sock to docker: group docker not found"的解决方案

    安装Dock服务,主要命令是  yum install docker. 但是在启动的时候报错:warning msg="could not change group /var/run/doc ...

  4. C#隐式转换与显示转换

    System.Objec时C#中所有类型的基类,也就是万类之源. 一.值类型 值类型都继承自System.ValueType(派生自System.Objec),继承自System.ValueType的 ...

  5. Ubuntu 16.04 安装系统监视器System Monitor

    安装好Ubuntu 16.04 之后,如何查看系统进程,CPU等的使用情况呢,System Monitor可以做到, 安装步骤: sudo add-apt-repository ppa:fossfre ...

  6. Jquery消息提示插件toastr使用详解

    toastr是一个基于jQuery简单.漂亮的消息提示插件,使用简单.方便,可以根据设置的超时时间自动消失. 1.使用很简单,首选引入toastr的js.css文件 html <script s ...

  7. matlab导入txt数据画图

    因为最近需要观察txt保存的一堆数据,则需要使用这些数据画图.强大的matlab分分钟解决了. 实例数据:data.txt 步骤: ①打开matlab -> HOME(主页) -> Imp ...

  8. SQL 语法使用

    SQL 语句 语句 语法 AND / OR SELECT column_name(s)FROM table_nameWHERE conditionAND|OR condition ALTER TABL ...

  9. 001_python实现数据分析

    一. # coding:utf8 # !/usr/bin/python # import numpy as np import pandas as pd import np def example2( ...

  10. pytorch中文文档-torch.nn.init常用函数-待添加

    参考:https://pytorch.org/docs/stable/nn.html torch.nn.init.constant_(tensor, val) 使用参数val的值填满输入tensor ...