[BJWC2010] 严格次小生成树
传送门:>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] 严格次小生成树的更多相关文章
- [BJWC2010]严格次小生成树(LCA,最小生成树)
[BJWC2010]严格次小生成树 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图 ...
- P4180 [BJWC2010]严格次小生成树
P4180 [BJWC2010]严格次小生成树 P4180 题意 求出一个无向联通图的严格次小生成树.严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次 ...
- 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...
- 洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】
严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...
- BZOJ1977/LuoguP4180【模板】严格次小生成树[BJWC2010] (次小生成树)
这道题本身思维难度不大,但综合性强,细节多 在其上浪一个早上,你的 最小生成树 树链剖分 线段树 DEBUG能力... 都大幅提升 细节与思路都在代码里面了. 欢迎hack. #include< ...
- P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...
- 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】
P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...
- 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- Luogu P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...
随机推荐
- Intellij Idea 教程
Intellij Idea 教程 [涵盖安装.配置.常见问题&技巧.Maven.Git.Tomcat.快捷键.项目配置等] 目录 入门............................. ...
- prometheus排错
1.导入grafana模板后node-export某些图像无法获取到data: 解决:导入grafana 模板是需要看node-export 版本是否与模板要求的一致,不同版本的node-export ...
- 用PhoneGap创建第一个项目
1.在eclipse中新建Android Project2.在项目的目录下,建两个文件夹:/libs/assets/www3.进入将刚刚下载并解压的PhoneGap包里Anroid目录,我们需要的资源 ...
- session与cookie的区别以及HTML5中WebStorage理解
一.session与cookie的区别 二.HTML5中WebStorage理解 WebStorage的目的是克服由cookie所带来的一些限制,当数据需要被严格控制在客户端时,不需要持续的将数据发回 ...
- anaconda 出现add 。。。进不去
找到.condarc 文件 C:\Users\leiyi内 把里面内容替换为 channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pk ...
- Python_字典及其操作
字典 概念 字典,Python基础数据类型之一,{}以键值对的形式存储数据. 以key : value 形式存储数据.例如,name 为 key,Laonanhai 为 value. dic = {' ...
- 【转】redis-cluster安装配置
需要三台虚拟机(生产环境是3个物理机),分配静态IP.cluster中共6个节点.3主3从.本文中每个虚拟机上的redis端口:6379 6380. 需要注意的两点: 3个主节点分别位于3台虚拟机上, ...
- centos yum install nginx
nginx newshttp://nginx.org/ nginx news: 2017http://nginx.org/2017.html nginx: Linux packageshttps:// ...
- js在微信、微博、QQ、Safari唤起App的解决方案
首先看下完整的流程: 简单说下universal link 在iOS9之前,唤起方式和现在安卓是一个的,都是使用scheme进行唤起,这种方式有个小问题,每次唤起,都会给个提示:是否打开xx应用,这样 ...
- vue单页面模板说明文档(1)
Introduction This boilerplate is targeted towards large, serious projects and assumes you are somewh ...