使用 Link Cut Tree 维护最小生成树
简介
本文将简单介绍如何使用 Link Cut Tree 维护动态图最小生成树。
思路
最小生成树的性质:一个基环树的最小生成树,为将环上边权最大的边删除后所组成的树。
Proof:如果删除环上的其他边,那么删除的边的权一定不大于最大边的边权。所以删最大权的边的树的边权和比其他的都要小。符合最小生成树定义。
如果我们插入边 \((u,v,w)\)。先判断 \(u,v\) 之间是否连通(这个可以简单的用 LCT 完成,不会的去做 P2147 [SDOI2008] 洞穴勘测)。
- 如果不连通,那么就最小生成树上(就是 LCT 上)连边 \((u,v)\)。
- 如果连通,那么先找到路径 \((u,v)\) 上边权最大的边,如果它的边权小于等于 \(w\),那么我们要插入的边是“废边”,直接忽略。否则将边权最大的边 Cut 掉,连上 \((u,v,w)\)。
注意到 LCT 无法直接维护边权,于是我们可以将边拆点之后维护(如果不会去做 SPOJ QTREE - Query on a tree)。
至此,以上操作全部可以用 LCT 完成(只需要维护最大值和最大值位置)。时间复杂度单次期望 \(O(\log n)\)。
代码
这里以 P3366 【模板】最小生成树 为例。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 4e5+5;
namespace LCT{
#define ls (son[i][0])
#define rs (son[i][1])
int son[N][2];
int fa[N];
bool tag[N];
int maxt[N],maxid[N];
int val[N];
inline void pushup(int i){
maxt[i]=val[i],maxid[i]=i;
if(maxt[ls]>maxt[i]){
maxt[i]=maxt[ls];maxid[i]=maxid[ls];
}
if(maxt[rs]>maxt[i]){
maxt[i]=maxt[rs];maxid[i]=maxid[rs];
}
}
inline void reverse(int i){
swap(ls,rs);tag[i]^=1;
}
inline void pushdown(int i){
if(tag[i]){
if(ls) reverse(ls);
if(rs) reverse(rs);
tag[i]=0;
}
}
inline bool get(int i){
return son[fa[i]][1]==i;
}
inline bool is_root(int i){
return son[fa[i]][0]!=i && son[fa[i]][1]!=i;
}
void update(int i){
if(!is_root(i)){
update(fa[i]);
}
pushdown(i);
}
inline void rotate(int p){
int q=fa[p],z=fa[q],k=get(p);
if(!is_root(q)){
son[z][son[z][1]==q]=p;
}
fa[p]=z;
son[q][k]=son[p][!k];
if(son[p][!k]) fa[son[p][!k]]=q;
son[p][!k]=q;
fa[q]=p;
pushup(q);
pushup(p);
}
inline void splay(int i){
update(i);
for(int f;f=fa[i],!is_root(i);rotate(i)){
if(!is_root(f)){
rotate(get(f)==get(i)?f:i);
}
}
}
inline void access(int i){
int p;
for(p=0;i;p=i,i=fa[i]){
splay(i);
son[i][1]=p;
pushup(i);
}
}
inline int find(int i){
access(i);
splay(i);
while(ls) pushdown(i),i=ls;
splay(i);
return i;
}
inline void make_root(int i){
access(i);
splay(i);
reverse(i);
}
inline void split(int u,int v){
make_root(u);
access(v);splay(v);
}
inline void link(int u,int v){
make_root(u);
if(find(v)!=u){
fa[u]=v;
}
}
inline void cut(int i){
splay(i);
fa[ls]=fa[rs]=0;
}
}
int ret=0,ec=0;
signed main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
LCT::val[i+n]=w;
if(LCT::find(u)!=LCT::find(v)){
LCT::link(u,i+n);LCT::link(i+n,v);
ret += w;
ec++;
continue;
}
LCT::split(u,v);
int mxid=LCT::maxid[v],mxv=LCT::maxt[v];
if(mxv<=w) continue;
ret -= mxv;
LCT::cut(mxid);
LCT::link(u,i+n);
LCT::link(i+n,v);
ret += w;
}
if(ec==(n-1)) cout<<ret;
else cout<<"orz";
return 0;
}
习题
使用 Link Cut Tree 维护最小生成树的更多相关文章
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- Link Cut Tree 总结
Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...
- Link/cut Tree
Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)
题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...
- Luogu 3690 Link Cut Tree
Luogu 3690 Link Cut Tree \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码. 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Lin ...
- [BJOI2014]大融合(Link Cut Tree)
[BJOI2014]大融合(Link Cut Tree) 题面 给出一棵树,动态加边,动态查询通过每条边的简单路径数量. 分析 通过每条边的简单路径数量显然等于边两侧节点x,y子树大小的乘积. 我们知 ...
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题
A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...
随机推荐
- 后端框架的学习----mybatis框架(7、使用注解开发)
7.使用注解开发 1.注解在接口上实现 /** * 查询用户 */ @Select("select * from user") public List<User> ge ...
- Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
文章目录 1.列表排序 1.1 .代码实例 1.2 .测试效果 1.3.需要掌握的前提知识 2.Vue监测数据变化的原理 2.1.代码实例 2.2 .测试效果 3.Vue检测数据的原理 3.1 基本知 ...
- 深入理解独占锁ReentrantLock类锁
ReentrantLock介绍 [1]ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程 ...
- VSCode设置鼠标滚轮滑动设置字体大小
1. 打开"文件->首选项->设置 2. 打开settings.json文件 3. 在setting.json 中添加"editor.mouseWheelZoom&qu ...
- 三十三、HPA实现自动扩缩容
通过HPA实现业务应用的动态扩缩容 HPA控制器介绍 当系统资源过高的时候,我们可以使用如下命令来实现 Pod 的扩缩容功能 $ kubectl -n luffy scale deployment m ...
- k8s集权IP更换
-.背景描述 背景:在场内进行部署完成后标准版产品,打包服务器到客户现场后服务不能正常使用,因为客户现场的IP地址不能再使用场内的IP,导致部署完的产品环境在客户现场无法使用:此方案就是针对这一问题撰 ...
- Java安全之CC4,5,7
前言 前边已经将CC链中的关键部分学习差不多,接下来就是一些扩展思路, CC4 ObjectInputStream.readObject() PriorityQueue.readObject() Pr ...
- laravel的_token传值 ; header中传_token
laravel框架中只要是涉及到post传值都需要传 _token ,这是框架中为了防止crsf攻击所做的安全措施,那么我们用到ajax中的post 方式传值时,也需要在所传数据中添加一个_token ...
- gin-k8s 运行的问题
1,k8s admin dashboard项目地址:https://github.com/kubernetes/dashboard项目使用的是golang 作为后端,然后使用angular 作为前段框 ...
- CentOS 7.x字符界面安装图形界面方法
1. 配置好yum源,可以使用光盘镜像源,也可以使用网络源. 阿里源下载示例: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.ali ...