其实也不是多难的知识点吧……学了一个中午+半个下午就把它学会了(做过那道 jxd 作业 CF571D 的应该比较好理解)

Kruskal 重构树大概就是在正常 Kruskal 的时候,对于两个需要连边的点 \(u,v\) 不直接连边,而是新增一个虚拟节点 \(T\),权值为 \(u,v\) 间的边权 \(w\),并连边 \(T\to u,T\to v\)。

下图可以较为清楚地展示 Kruskal 重构树的过程,正常的 Kruskal 我们是这样连边的:

而 Kruskal 重构树我们是这样连边的:

显然这样建出来的图是一棵树,而这棵树有以下性质:

  1. 由于我们每个新建的点都恰好连出的两条边,因此这棵树是一个二叉树
  2. 由于我们是按照边权从小到大排序来建树的,因此这棵树的权值可以看作一个大根堆(假设叶子节点的权值为 \(0\) 或 \(-\infty\))
  3. 对于两个点 \(u,v\),它们之间路径最大值的最小值就是 Kruskal 重构树上它们 LCA 的权值,这个用普通的 Kruskal 建出最小生成树再查询它们之间路径权值最大值的方法也可说明
  4. 对于一个点 \(u\),记 \(v\) 为离 \(u\) 最远的满足 \(v\) 的权值 \(\le w\) 的 \(u\) 的祖先,那么所有 \(u\) 经过权值 \(\le w\) 的边能够到达的点的集合恰好为 \(v\) 子树内所有叶子节点,这个性质相当重要,因为它可以将我们陌生的图的连通性问题转化为熟悉的子树问题,而这恰恰是可以通过 DFS 序套上某些数据结构维护的。

Kruskal 重构树的知识点就这么多,实现起来不算太难,只不过有以下需要注意的地方:

  1. Kruskal 重构树点数最多会达到 \(2n-1\),因此要开两倍空间
  2. 如果题目图不连通,那么最后建出的 Kruskal 重构树也不连通,也就是说最后得到的是一个二叉森林,此时就要额外补上一个节点 \(R\),权值为 \(\infty\),并将 \(R\) 与森林中所有连通块的根节点之间连边(当然这样得到的树就不是二叉树了)

代码想想还是贴一下罢(当然这是题目保证连通的情况的代码,如果题目没保证连通那后面还要加上两三句话,由于过于简单就不贴了):

int hd[MAXN*2+5],nxt[MAXN*2+5],to[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int f[MAXN*2+5],nc;
int main(){
nc=n;for(int i=1;i<=n;i++) f[i]=i;
for(int i=1,u,v;i<=m;i++){
u=find(u);v=find(v);if(u==v) continue;++nc;
f[u]=f[v]=f[nc]=nc;adde(nc,u);adde(nc,v);val[nc]=i;
}
}

总之,Kruskal 重构树无法解决权值之和最小的问题,它只能解决路径上权值最大值最小最小值最大可达性问题,因此看到类似于”只经过权值 \(\le w\) 的边“或者”能够到达的点当中“等字眼就可以联想到 Kruskal 重构树。

例题:

1. AT1998 [AGC002D] Stamp Rally

差点不会做,身败名裂

首先以边的编号为权值建出 Kruskal 重构树,对每个询问考虑二分,二分答案 \(mid\),那么显然可以倍增找出 \(x\) 可以到达的点和 \(y\) 可以到达的点,显然是两个子树 \(u\) 和 \(v\) 的并,而这个并的大小可用通过判断 \(u,v\) 是否存在祖先关系求出,如果存在就是祖先子树大小,否则就是 \(siz_u+siz_v\),将它与 \(z\) 比较即可。

时间复杂度 \(n\log^2n\),可能有 \(n\log n\) 的做法,不过估计 Kruskal 重构树是做不了了(

u1s1 倍增是真的喜欢和 Kruskal 重构树贴贴(大雾

2. P4197 Peaks

还是建出 Kruskal 重构树,倍增找出对应子树 \(u\),然后建立主席树,在主席树上离散化+二分找第 \(k\) 大即可。

时间复杂度 \(n\log n\)。

好套路啊……

3. CF1416D Graph and Queries

考虑离线,对每条边记它的边权为它被删除的时间(如果没被删除则为 \(q+1\)),然后建 Kruskal 重构树(这次要建个大根堆,因为可以访问的边的边权要大于某个数),然后对每个询问还是倍增找出它可以到达的点,然后线段树+DFS 序找出子树内权值最大的点赋为 \(0\) 即可。

时间复杂度 \(n\log n\)。

4. P4768 [NOI2018] 归程

首先最优方案肯定是开一段距离的车然后走一段距离,而由于终点都是 \(1\) 且图为无向图,因此可以 dijkstra(关 于 S P F A,它 死 了,死 于 这 道 题 的 手 中)求出 \(1\) 到每个点的最短距离 \(dis_i\),那么每个询问的答案就是 \(v\) 能到达的点中 \(dis\) 的最小值,这个显然是可以 Kruskal 重构树解决的,而且甚至不用什么数据结构(不愧是你 NOI 签到题),直接记录一个子树最小值即可。

时间复杂度 \(Tn\log n\)。

5. P4899 [IOI2018] werewolf 狼人

我竟然能独立想出来近几年 IOI 的题,incredible!

首先题目等价于能否找到一个编号在 \([L_i,R_i]\) 之间的点 \(t\),满足存在 \(U_i\to t\),只经过编号 \(\ge L_i\) 的点的路径,也存在 \(t\to V_i\),只经过编号 \(\le R_i\) 的路径。

这东西显然是可以 Kruskal 重构树的,比较棘手的一点是此题涉及点权,而不是边权。不过事实上转化非常容易,显然对于一条边 \((u,v)\) 而言,只有 \(u,v\) 的权值都符合要求,\((u,v)\) 才能通过,那么我们就可以把 \((u,v)\) 的权值设为 \(\min(w_u,w_v)\)(如果要求经过的边权值 \(\ge v\))或者 \(\max(w_u,w_v)\)(如果要求经过的边权值 \(\le v\)),这样就可以 Kruskal 重构树了。

于是现在题目转化为,对于有两棵树,\(q\) 组询问,每组询问给出第一棵树上的点 \(u\) 和第二棵树上的点 \(v\),判断是否存在一个叶子节点在 \(u,v\) 的子树中,这个可以使用 DFS 序转化为区间问题,然后就可以主席树维护了,有点类似于这个题,时间复杂度 \(n\log n\)

Kruskal 重构树小记的更多相关文章

  1. [bzoj 3732] Network (Kruskal重构树)

    kruskal重构树 Description 给你N个点的无向图 (1 <= N <= 15,000),记为:1-N. 图中有M条边 (1 <= M <= 30,000) ,第 ...

  2. 【BZOJ 3732】 Network Kruskal重构树+倍增LCA

    Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT ...

  3. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  4. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  5. bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...

  6. kruskal重构树学习笔记

    \(kruskal\) 重构树学习笔记 前言 \(8102IONCC\) 中考到了,本蒟蒻不会,所以学一下. 前置知识 \(kruskal​\) 求最小(大)生成树,树上求 \(lca​\). 算法详 ...

  7. Kruskal重构树入门

    这个知识点好像咕咕咕了好长了..趁还没退役赶紧补一下吧.. 讲的非常简略,十分抱歉.. 前置知识 Kruskal算法 一定的数据结构基础(如主席树) Kruskal重构树 直接bb好像不是很好讲,那就 ...

  8. UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html 题解 套路啊. 先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵krus ...

  9. LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)

    LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...

随机推荐

  1. WPF中的命令(Command)

    这节来讲一下WPF中的命令(Command)的使用. [认识Command] 我们之前说过,WPF本身就为我们提供了一个基础的MVVM框架,本节要讲的命令就是其中一环,通过在ViewModel中声明命 ...

  2. 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)

    前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...

  3. Java:Object对象小记

    Java:Object对象小记 对 Java 中的 Object 对象,做一个微不足道的小小小小记 Object 的常用方法有哪些 clone() 方法:用于创建并返回当前对象的一份拷贝: 在Java ...

  4. [敏捷软工团队博客]Beta阶段发布声明

    项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段发布声明 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...

  5. gson中TypeAdapter实现自定义序列化操作

    最近在项目中遇到这么一个问题,我们后台需要向前端返回一个 json 数据,就是将一个地理位置对象以json的格式返回到前台,但是这个地理位置对象中的经纬度是Double数据类型,项目中规定,如果经纬度 ...

  6. 嵌入式单片机stm32之DMA实验

    一. 对于大容量的STM32芯片有2个DMA控制器,控制器1有7个通道,控制器2有5个通道 每个通道都可以配置一些外设的地址. 二. 通道的配置过程: 1. 首先设置CPARx寄存器和CMARx寄存器 ...

  7. Shell脚本学习笔记之(自动填充函数模板)

    其实,vii 就是写的一个脚本,跟 vi 没半毛钱关系,只不过借用一下这个名字而已.那这个脚本长什么样呢?look: 下面来详细的解析上面的代码,来看第1行: #!/bin/bash 这是Shell脚 ...

  8. AOP源码解析:AspectJExpressionPointcutAdvisor类

    先看看 AspectJExpressionPointcutAdvisor 的类图 再了解一下切点(Pointcut)表达式,它指定触发advice的方法,可以精确到返回参数,参数类型,方法名 1 pa ...

  9. 转:Linux常用命令总结

    学习linux也有一阵子了,现总结一些常用的linux操作命令,方便大家查找1. cd命令这个命令是最基本的也是最常用的.它用于切换当前目录,可以是绝对路径,也可以是相对路径.例:cd /root/h ...

  10. 猫狗收容所 牛客网 程序员面试金典 C++

    猫狗收容所 牛客网 程序员面试金典 C++ 题目描述 有家动物收容所只收留猫和狗,但有特殊的收养规则,收养人有两种收养方式,第一种为直接收养所有动物中最早进入收容所的,第二种为选择收养的动物类型(猫或 ...