简介

本文将简单介绍如何使用 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. 关于TP5模板输出时间戳问题--A non well formed numeric value encountered

    某日.因为一个项目.控制器我是这么写的 1 /** 2 * get admin/Picture/index 3 * 显示所有图册信息 4 * @return view 5 */ 6 public fu ...

  2. v-for和router-link的共同使用

    1. 错误例子 <div style="color: red" v-for="item in pressionList" :key="item. ...

  3. 18.-cookies和session

    一.会话定义 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次绘画 HTTP协议是无状态的,导致绘画状态难以保持 Cookies和session就是为了保持会话状态而诞生的两个存储技术 ...

  4. 十八、Service的应用

    Service 的应用 ClusterIP ​clusterIP 主要在每个 node 节点使用 ipvs,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中.然后 kube ...

  5. Istio(十三):Istio项目实际案例——Online Boutique

    目录 一.模块概览 二.系统环境 三.创建Kubernetes(k8s)集群 3.1 创建Kubernetes(k8s)集群 3.2 Kubernetes集群环境 四.安装istio 4.1 安装Is ...

  6. 各种优化器对比--BGD/SGD/MBGD/MSGD/NAG/Adagrad/Adam

    指数加权平均 (exponentially weighted averges) 先说一下指数加权平均, 公式如下: \[v_{t}=\beta v_{t-1}+(1-\beta) \theta_{t} ...

  7. 分布式事务框架 Seata 入门案例

    1.  Seata Server 部署 Seata分TC.TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成. 首先,下载最新的安装包 也可以下载源 ...

  8. excel公式与快捷操作

    将首行的公式,运用到这一整列 1.选中要输入公式的第一个单元格,SHIFT+CTRL+方向键下,在编辑栏中输入公式,按下CTRL+回车: 2.先输入要填充的公式,按下SHIFT+CTRL+方向键下,再 ...

  9. ansible回调插件介绍(待完成)

    简介 ansible回调插件(callback plugins)允许为事件添加一些额外响应.这里的事件包括了执行任务(task)的结果,例如(ok.failed.unreachable.skipped ...

  10. 2022春每日一题:Day 37

    题目:[USACO14FEB]Auto-complete S 字典树套路题,字典树优化剪枝,加个cnt标记即可 代码: #include <cstdio> #include <cst ...