首页 > 其他分享 >使用 Link Cut Tree 维护最小生成树

使用 Link Cut Tree 维护最小生成树

时间:2023-01-01 22:12:36浏览次数:64  
标签:LCT Cut int void Tree son fa Link inline

简介

本文将简单介绍如何使用 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] 魔法森林

标签:LCT,Cut,int,void,Tree,son,fa,Link,inline
From: https://www.cnblogs.com/zheyuanxie/p/mst-by-lct.html

相关文章

  • Flink:状态编程
    Flink中的状态在流处理中,数据是连续不断到来的。每个任务进行计算处理时,可以基于当前数据直接转换得到输出结果,也可以依赖一些其他数据。这些由一个任务维护,并且用来计算......
  • CodeForces 1726E Tree Sum
    洛谷传送门CF传送门不错的一道Combinatorics。结论1:\(n\)为奇数时答案为\(0\)。设\(d_i\)为与点\(i\)相连的边边权乘积。每加入一条边对两端的\(d_i\)贡献......
  • OpenOCD+DAP-LINK调试ESP32的失败经历
    目的手里有调试STM32的DAP-LINK,想试试通过JTAG调试ESP32OpenOCD支持CMSIS-DAPDAP-LINK支持的芯片,我手上这款描述如下,应该JTAG协议的都支持平台windows10+ESP-IDFE......
  • 黏菌优化算法SMA(Matlab完整代码实现)求解热电联产经济调度问题的改进遗传与粒子群算法S
    黏菌优化算法SMA在电力系统中虽然有所应用,但是发表的文章还是比较少的,所有这个算法的应用空间还很广,推荐推荐:对于这两篇文献,我写过相关的文章,先回顾一下,然后再开始今天的话......
  • fix协议介绍13-执行报告(ExecutionReport)
    FIX.5.0SP2MessageExecutionReport [type'8']<ExecRpt>Theexecutionreportmessageisusedto:1.confirmthereceiptofanorder2.confirmchangesto......
  • java中的LinkedList的add()源码解析
    一.介绍LinkedList类阐明LinkedList类的成员:其本质是双向链表,first指向链表的头部,last指向链表的尾部。二.介绍LinkedList静态内部类Node类阐明Nod......
  • OpenOCD如何通过stlink直接下载程序到stm32板子(已解决)
    首先,关于OpenOCD的入门介绍,以及如何调试,看我这篇文章:​​嵌入式IDE原理OpenOCD介绍以及stlink如何连接stm32板子_标biao的博客-由于OpenOCD一旦连接上,会自动进入3种端口监......
  • Flink Shuffle 3.0: Vision, Roadmap and Progress
    摘要:本文整理自阿里云高级技术专家宋辛童(五藏),在FFA2022核心技术专场的分享。本篇内容主要分为五个部分:FlinkShuffle的演进流批融合云原生自适应Shuffle3.0一、Flin......
  • FFA 2022 主会场 Keynote:Flink Towards Streaming Data Warehouse
    摘要:本文整理自ApacheFlink中文社区发起人、阿里巴巴开源大数据平台负责人王峰(莫问),在FlinkForwardAsia2022主会场的分享。本篇内容主要分为四个部分:实时流计算全球......
  • Flink 在米哈游的应用实践
    摘要:本文整理自米哈游大数据实时计算团队负责人张剑,在FFA的分享,本篇内容主要分为三个部分:发展历程和平台建设场景应用实践未来展望一、发展历程和平台建设米哈游成立于20......