简介

本文将简单介绍如何使用 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;
}

习题

P2387 [NOI2014] 魔法森林

使用 Link Cut Tree 维护最小生成树的更多相关文章

  1. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  2. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  3. Link Cut Tree 总结

    Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...

  4. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  5. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  6. 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)

    题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  7. Luogu 3690 Link Cut Tree

    Luogu 3690 Link Cut Tree \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码. 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Lin ...

  8. [BJOI2014]大融合(Link Cut Tree)

    [BJOI2014]大融合(Link Cut Tree) 题面 给出一棵树,动态加边,动态查询通过每条边的简单路径数量. 分析 通过每条边的简单路径数量显然等于边两侧节点x,y子树大小的乘积. 我们知 ...

  9. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

  10. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

随机推荐

  1. How to get the return value of the setTimeout inner function in js All In One

    How to get the return value of the setTimeout inner function in js All In One 在 js 中如何获取 setTimeout ...

  2. Windows docker环境安装

    前期准备 1.hyper-v功能 win10家庭版没有提供hyper-v的问题可通过如下脚本解决,保存为bat并运行重启电脑即可. pushd "%~dp0" dir /b %Sy ...

  3. CSS line-break属性与中文标点换行

    关于标点符号把文字带着换行的问题解决方案 出现的问题 最近在弄一个介绍页面的时候遇到一个很巧的问题,在文本换行的时候刚好能够放下文字,但是标点符号把这个文字带着换行了 如下图所示: 如果的在上一行显示 ...

  4. Vue3 企业级优雅实战 - 组件库框架 - 2 初始化 workspace-root

    上文已经搭建了 pnpm + monorepo 的基础环境,本文对 workspace-root 进行初始化配置,包括:通用配置文件.公共依赖.ESLint. 1 通用配置文件 在项目 根目录 下添加 ...

  5. 带你从0到1开发AI图像分类应用

    摘要:通过一个垃圾分类应用的开发示例,介绍AI Gallery在AI应用开发流程中的作用. 本文分享自华为云社区<AI Gallery:从0到1开发AI图像分类应用>,作者: yd_269 ...

  6. 【翻译】Spring Security抛弃了WebSecurityConfigurerAdapter

    原文链接:Spring Security without the WebSecurityConfigurerAdapter 作者:ELEFTHERIA STEIN-KOUSATHANA 发表日期:20 ...

  7. MongoDB - 事务支持

    事务简介 事务是数据库中处理的逻辑单元,每个事务中包括一个或多个数据库操作,既可以是读操作,也可以是写操作. ACID 是一个"真正"事务所需要具备的一组属性集合,指的是原子性(A ...

  8. Qt5 如何在designer中给工具栏(QToolBar)添加分割线

    如图分割线 方法1: 在工具栏右键,选择"添加分割符" 方法2: 在对象窗口中右键 toolBar ,选择"添加分割符" 其它 删除分割符,只能在布局窗口直接右 ...

  9. 一文带你快速入门 Go 语言微服务开发 - Dubbo Go 入门实践总结

    更多详细示例可直接访问 Dubbo 官网 或搜索关注官方微信公众号:Apache Dubbo 1. 安装Go语言环境 建议使用最新版 go 1.17 go version >= go 1.15 ...

  10. 【Java SE进阶】Day08 File类、递归

    一.File类 1.概述java.io.File 文件和路径的抽象表示 用于文件和目录的创建.查找和删除等 分类 file--文件 directory--文件夹/目录 path--路径 2.静态成员变 ...