传送门:>Here<

给出一张带权无向图,求其严格次小生成树。($n \leq 10^5$)

解题思路

图的生成树有一个性质:将一条非树边加入后必定形成环。Kruscal求最小生成树其实就是一个贪心地过程:剔除每个环上最大的那一条边。

那么反过来,求次小生成树就是在某个环上换回最大边,删去原来最大边以保证增量最小的过程。由于题目要求严格,会碰到最大边等于原先最大边的情况,此时就删去原先严格次大边。

于是现在就是一个数据结构维护的问题了。预处理出最小生成树,维护树链上最大值和次大值,可以树剖或者在倍增LCA的过程中维护。

如果够无聊,LCT也可以。LCT求最小生成树不用预先对边排序,由于可以动态连边断边,是完全可以根据最小生成树的性质直接维护的——每发现一条边形成了环,如果更优就直接LinkCut更新,保证了全局的最优性。再在Splay上维护边权的最小值就解决了。

$Code$

/*By QiXingzhi*/
#include <cstdio>
#include <vector>
#include <algorithm>
#define N (100010)
#define M (300010)
#define INF (21474836470000)
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
typedef long long ll;
using namespace std;
#define int ll
inline void read(int &x){
x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) +(x << ) + c - '', c = getchar(); x *= w;
}
struct Edge{
int x,y,z;
};
struct Graph{
int to,cost;
};
Edge a[M];
bool t_edge[M];
vector <Graph> G[N];
vector <Graph> Gt[N];
int n,m,krus,krus_num,x,y,ans;
int par[N],f[N][],gmax[N][],gsec[N][],fa[N],wei[N],depth[N];
inline void AddEdge(int u, int v, int w){
Graph e;
e.to = v;
e.cost = w;
G[u].push_back(e);
}
inline void AddEdge_2(int u, int v, int w){
Graph e;
e.to = v;
e.cost = w;
Gt[u].push_back(e);
}
inline void Swap(int& a, int &b){
int t = a;
a = b;
b = t;
}
inline bool kruscal_sort_comp(const Edge& a, const Edge& b){
return a.z < b.z;
}
int krus_find(int x){
if(par[x] == x) return x;
par[x] = krus_find(par[x]);
return par[x];
}
void build_tree(int x, int ff){
int sz = Gt[x].size();
int to;
for(int i = ; i < sz; ++i){
to = Gt[x][i].to;
if(to != ff){
fa[to] = x;
wei[to] = Gt[x][i].cost;
build_tree(to, x);
}
}
}
void lca_dfs(int x, int d){
depth[x] = d;
for(int k = ; (<<k) < d; ++k){
f[x][k] = f[f[x][k-]][k-];
gmax[x][k] = Max(gmax[x][k-], gmax[f[x][k-]][k-]);
if(gmax[x][k-] == gmax[f[x][k-]][k-]){
gsec[x][k] = Max(gsec[x][k-], gsec[f[x][k-]][k-]);
}
else if(gmax[x][k-] > gmax[f[x][k-]][k-]){
gsec[x][k] = Max(gsec[x][k-], gmax[f[x][k-]][k-]);
}
else if(gmax[x][k-] < gmax[f[x][k-]][k-]){
gsec[x][k] = Max(gmax[x][k-], gsec[f[x][k-]][k-]);
}
}
int sz = Gt[x].size();
int to;
for(int i = ; i < sz; ++i){
to = Gt[x][i].to;
if(to != f[x][]){
lca_dfs(to, d+);
}
}
}
inline void Update(int i){
int u = a[i].x, v = a[i].y, w = a[i].z, res;
int val1 = -INF, val2 = -INF;
if(depth[u] > depth[v]) Swap(u,v);
for(int k = ; k >= ; --k){
if(depth[u] <= depth[v] - (<<k)){
if(gmax[v][k] < val1){
val2 = Max(gmax[v][k], val2);
}
else if(gmax[v][k] == val1){
val2 = Max(val2, gsec[v][k]);
}
else if(gmax[v][k] > val1){
val2 = Max(gsec[v][k], val1);
}
val1 = Max(val1, gmax[v][k]);
v = f[v][k];
}
}
if(u != v){
for(int k = ; k >= ; --k){
if(f[u][k] != f[v][k]){
if(gmax[u][k] < val1){
val2 = Max(val2, gmax[u][k]);
}
else if(gmax[u][k] == val1){
val2 = Max(val2, gsec[u][k]);
}
else{
val2 = Max(val1, gsec[u][k]);
}
if(gmax[v][k] < val1){
val2 = Max(val2, gmax[v][k]);
}
else if(gmax[v][k] == val1){
val2 = Max(val2, gsec[v][k]);
}
else{
val2 = Max(val1, gsec[v][k]);
}
val1 = Max(val1, gmax[u][k]);
val1 = Max(val1, gmax[v][k]);
u = f[u][k];
v = f[v][k];
}
}
val1 = Max(val1, Max(gmax[u][], gmax[v][]));
if(val2 < gmax[u][] && gmax[u][] < val1) val2 = gmax[u][];
if(val2 < gmax[v][] && gmax[v][] < val1) val2 = gmax[v][];
}
if(val1 < w){
res = krus - val1 + w;
}
else if(val1 == w){
res = krus - val2 + w;
}
ans = Min(ans, res);
}
#undef int
int main(){
#define int ll
// freopen(".in","r",stdin);
read(n), read(m);
for(int i = ; i <= m; ++i){
read(a[i].x), read(a[i].y), read(a[i].z);
AddEdge(a[i].x,a[i].y,a[i].z);
AddEdge(a[i].y,a[i].x,a[i].z);
}
sort(a+, a+m+, kruscal_sort_comp);
for(int i = ; i <= n; ++i) par[i] = i;
for(int i = ; i <= m; ++i){
x = krus_find(a[i].x);
y = krus_find(a[i].y);
if(x != y){
par[x] = y;
++krus_num;
krus += a[i].z;
t_edge[i] = ;
AddEdge_2(a[i].x,a[i].y,a[i].z);
AddEdge_2(a[i].y,a[i].x,a[i].z);
}
if(krus_num >= n-) break;
}
build_tree(, );
for(int i = ; i <= n; ++i){
f[i][] = fa[i];
gmax[i][] = wei[i];
gsec[i][] = -INF;
}
lca_dfs(,);
ans = INF;
for(int i = ; i <= m; ++i){
if(!t_edge[i]){
Update(i);
}
}
printf("%lld",ans);
return ;
}

[BJWC2010] 严格次小生成树的更多相关文章

  1. [BJWC2010]严格次小生成树(LCA,最小生成树)

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

  2. P4180 [BJWC2010]严格次小生成树

    P4180 [BJWC2010]严格次小生成树 P4180 题意 求出一个无向联通图的严格次小生成树.严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次 ...

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

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

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

    严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...

  5. BZOJ1977/LuoguP4180【模板】严格次小生成树[BJWC2010] (次小生成树)

    这道题本身思维难度不大,但综合性强,细节多 在其上浪一个早上,你的 最小生成树 树链剖分 线段树 DEBUG能力... 都大幅提升 细节与思路都在代码里面了. 欢迎hack. #include< ...

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

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

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

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

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

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

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

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

随机推荐

  1. centos安装RabbitMQ 3.7.9 (使用RPM)

    上篇我们提到不使用RPM安装RabbitMQ 3.7.8,其实我个人更倾向不使用RPM安装RabbitMQ,因为可以控制安装位置及设置参数. 存在即合理,使用RPM安装RabbitMQ,可以减少配置参 ...

  2. 个人实战演练全过程——No.1 最大连续子数组求和

    之前的一次个人总结和一次单元测试入门学习是开启软件工程课程的前奏曲,也是热身,现在大家对于这门课程也有了初步的了解和认识,这次要开始真正的演奏了,要从头到尾完全靠自己的能力来解决一个问题,进行实战演练 ...

  3. Wannafly summer camp Day6 - D 区间权值

    这道题实在是不该,我在化式子的时候,多此一举,把式子进行累加,导致自己当时化的式子是错的,这样导致自己卡了很久,也没想到好的思路,赛后重新分析一波,感觉巨™简单...难受的一逼. 这道题的关键在于,W ...

  4. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛D-80 Days--------树状数组

    题意就是说1-N个城市为一个环,最开始你手里有C块钱,问从1->N这些城市中,选择任意一个,然后按照顺序绕环一圈,进入每个城市会有a[i]元钱,出来每个城市会有b[i]个城市,问是否能保证经过每 ...

  5. Deflation Methods for Sparse PCA

    目录 背景 总括 Hotelling's deflation 公式 特点 Projection deflation 公式 特点 Schur complement deflation Orthogona ...

  6. JAVA项目中的常用的异常处理情况

    NO.1 java.lang.NullPointerException 这个异常比较容易遇到,此异常的解释是“程序遇上了空指针”,简单地说就是调用了未经初始化的对象或者是不存在的对象,这个错误经常出现 ...

  7. 我的集合学习笔记--ArrayList

    一,ArrayList 实现自己的ArrayList:主要是添加方法,理解自动扩容机制 代码+注释 package com.amazing.jdk.learn2List.list_08_13; /** ...

  8. semantic-ui 下拉框

    注意:在使用semantic的下拉框的时候,不仅需要引入semantic.css,还要引入semantic.js,最重要的是引入jquery.否则下拉效果不会显示. 并且,jquery必须先于sema ...

  9. [转帖]firewall-cmd

    firewall-cmd https://wangchujiang.com/linux-command/c/firewall-cmd.html 高手大作 等哪天需要防火墙了 再练习一下. Linux上 ...

  10. Centos6.8 安装nginx

    1.安装相关依赖 (1)yum install gcc 备注:可以通过gcc -v 查看版本信息,来确定是否安装过. (2)yum install pcre-devel (3)yum install ...