简介

本文将简单介绍如何使用 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. 一天一道Java面试题----第十二天(如何实现接口幂等性)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.如何实现接口幂等性 1.如何实现接口幂等性 唯一id.每次操作,都根据操作和内容生成唯一的id,在执行之前先判断id是 ...

  2. python: m个位置,每个位置有n种可能,求所有排列结果

    >>> import itertools >>> m, n = 3, 2 >>> paths = list(itertools.product(r ...

  3. vue3学习记录(新特性)

    总概 1) 性能提升 打包大小减少 41% 初次渲染快 55%,更新渲染快 133% 内存减少 54% 使用 Proxy 代替 defineProperty 实现数据响应式 重写虚拟 DOM 的实现和 ...

  4. Unity——射线检测(鼠标点击开关门效果)

    Unity射线检测--实现简单的开关门效果 简要:通过鼠标点击来发射一条射线,来获得射线所碰到的物体名称,再通过改变门的Rotation值来实现开关门的效果. 一.代码实现 1.1 简易的场景搭建 注 ...

  5. 二、Django下载与运行

    二.Django下载与运行 2.1.Django的下载 目前我们学习和使用的版本是3.2LTS版本 目前开源软件发布一般会有2个不同的分支版本: 1. 普通发行版本: 经常用于一些新功能,新特性,但是 ...

  6. 【性能测试】Loadrunner12.55(二)-飞机订票系统-脚本录制

    1.1 飞机订票系统 Loadrunner 12.55不会自动安装飞机订票系统,要自己手动安装. 我们需要下载Web Tools以及一个小插件strawberry https://marketplac ...

  7. Jmeter——请求响应内容乱码解决办法

    前段时间,换过一次设备,重新下载了Jmeter.有一次在编写脚本时,响应内容中的中文一直显示乱码. 遇到乱码不要慌,肯定是有办法来解决的.具体解决办法,可以参考之前的博文,Jmeter--BeanSh ...

  8. linux系统配置文件或shell脚本批量注释

    1. 配置文件批量注释 1.1 批量注释 ① 进入命令行模式,按ctrl + v进入 visual block模式,键盘上下箭头选中多行,把需要注释的行标记起来 ② 按大写字母I,再输入注释符:# ③ ...

  9. Paddle Graph Learning (PGL)图学习之图游走类模型[系列四]

    Paddle Graph Learning (PGL)图学习之图游走类模型[系列四] 更多详情参考:Paddle Graph Learning 图学习之图游走类模型[系列四] https://aist ...

  10. EntityFramework介绍

    首先我们说明一下ORM是什么. 微软官方提供的ORM工具,ORM让开发人员节省数据库访问的代码时间,将更多的时间放到业务逻辑层代码上.开发人员使用Linq语言,对数据库操作如同操作Object对象 一 ...