首页 > 其他分享 >图论相关

图论相关

时间:2024-09-25 11:38:11浏览次数:9  
标签:图论 重心 int dfs dfn LCA 相关 重链

图论

LCA

性质

  1. \(LCA(A \cup B) = LCA(LCA(A), LCA(B))\)
  2. 一堆点集的LCA 等于其中 dfn 最大的和最小的点的 LCA

dfs序求lca

好写且 \(O(1)\),吊打欧拉序和倍增。

如果两个点 \(x\) 和 \(y\) 不存在祖孙关系,那么 \(LCA(x,y) = fa(min(dfn_x, dfn_y))\)。

我们钦定 \(dfn_x < dfn_y\) 这里的 min() 是指 \([dfn_x, dfn_y]\) 之间深度最小的点的编号。

考虑证明很简单,思考dfn是怎么来的即可。

如果存在祖孙关系,那么 \(LCA = x\),但是为了方便写,我们可以把两种情况统一起来,我们将dfn_x加一即可,这样加一之后不影响第一种情况,第二种情况的答案也可以算到。

代码:

int dfn[N], tim, st[21][N];
void dfs(int u, int pre) {
	st[0][dfn[u] = ++tim] = pre;
	for(int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if(v == pre) continue;
		dfs(v, u);
	}
}
int Min(int x, int y) { return dfn[x] < dfn[y] ? x : y; }
void init() {
	for(int i = 1; i <= 20; i++) 
		for(int j = 1; j + (1 << i) - 1 <= n; j++) 
			st[i][j] = Min(st[i - 1][j], st[i - 1][j + (1 << i - 1)]);
}
int lca(int x, int y) {
	if(x == y) return x;
	if((x = dfn[x]) > (y = dfn[y])) swap(x, y);
	int d = 31 ^ __builtin_clz(y - x); x++;
	return Min(st[d][x], st[d][y - (1 << d) + 1]);
}

实际实现不需要dep和fa数组,具体细节见代码。

这个做法的瓶颈在RMQ,如果用一些高科技搞RMQ可以做到 \(O(n)~O(1)\),但基本常数较大且不怎么好些。

树剖求lca

\(O(n)~O(logn)\) 常数小,代码也比较简单,可以替代倍增,但最好的还是dfs序。

树的直径

两种方法:两次dfs或者树形DP。推荐第二种,因为好写且支持找负边权的直径,树形DP又有两种方法,这里写一种好写的。

不过有意义的,两次dfs的结论也可以记住:

在都是非负边权的情况下,从树上任意一点 \(x\) 出发,到达的最远的点 \(y\) 一定是直径的一端。

具体证明很简单,使用反证法,分三种情况分别考虑

  1. \(x\) 就在直径上
  2. \(x\) 不在直径上,但是求得的路径 \((a,b)\) 与直径 \((z, w)\) 有交点。
  3. 没有交点。

DP代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n, dp[N], ans;
void chmx(int &x, int y) { x = max(x, y); }
vector<int> G[N];
void dfs(int u, int fa) {
	for(int v : G[u]) if(v ^ fa) {
		dfs(v, u);
		chmx(ans, dp[u] + 1 + dp[v]);
		chmx(dp[u], 1 + dp[v]);
	}
}
int main() {
	scanf("%d", &n);
	for(int i = 1, u, v; i < n; i++)
		scanf("%d%d", &u, &v), G[u].push_back(v), G[v].push_back(u);
	dfs(1, 0);
	printf("%d", ans);
	return 0;
}

树的重心

性质

  1. 重心最多两个,如果有两个,那么肯定相邻。
  2. 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。(这个也是充要条件)
  3. 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。(这个性质也挺好)
  4. 要是通过一条边把两棵树连起来,那么新的重心在原来两棵树的重心的路径上。(有助于动态维护重心)
  5. 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离

证明: 先咕着。

树剖

长剖和实剖先不展开。主要就是重链剖分。
重链剖分及其擅长解决树上路径问题,他把树剖成了若干条重链,并且任意一条路径上最多 \(logn\) 条重链,这使得我们可以使用一些可以维护链上信息并且支持信息快速合并的数据结构来维护重链,并且树剖利用和拓展dfs序的性质,把链搞成一个区间,使得我们的维护更加的方便。
顺带着dfs序的性质,树剖对于子树信息的维护也很擅长。
具体算法内容就不赘述了,这里只做总结。

dsu on tree

也叫树上启发式合并,有些时候我们完全可以直接启发式合并,但是这个算法给了另一种启发式合并的思路,dsu on tree主要是对子树信息统计,具体算法很人类智慧,考虑我们要统计每个点的子树信息,并且只能用一个桶或者数据结构。

比如我们dfs目前到了节点 \(u\),我们会将 \(u\) 的儿子 \(v\) 一一递归下去,这样的话我们遍历完一个儿子就要清空桶,不然其他儿子的信息就不对,遍历完儿子之后我们再来统计 \(u\) 的信息,那么就有一个人类智慧,最后一个儿子遍历完不用清空,可以留下来给 \(u\) 用,这样就有了一个剪枝。再人类智慧的,我们可以钦定最后一个儿子是重儿子,这样剪枝最优。事实上,这已不仅仅是剪枝,而已经达到了 \(O(nlogn)\) 的复杂度了。

考虑证明:计算每个点会被统计几次,如果他在重链上,那么他的信息会被继承上去,不会重复统计,所以说一个点的统计次数就等于这个点到根的重链数量,也就是 \(O(logn)\),所以总时间复杂度 \(O(nlogn)\)。

虚树

虚树适用于某些题目,这些题目通常需要你做很多次树形DP,只有少部分点是我们DP需要的,我们可以根据他们的祖孙关系建出虚树,这样复杂度就降下来了。

标签:图论,重心,int,dfs,dfn,LCA,相关,重链
From: https://www.cnblogs.com/qerrj/p/18430977

相关文章

  • 算法题之图论 [NOIP2001 提高组] Car的旅行路线详细题解
    P1027[NOIP2001提高组]Car的旅行路线这道题的思路呢,就是建个图,然后跑一遍Floyd,比较最小值就可以解决了。but!它每个城市只给三个点(共四个),所以还得计算出第四个点坐标。这里根据矩形的中点公式来表示未知点的坐标:(这个思路源于大佬 _jimmywang_       ......
  • 计算机网络实验2——利用Wireshark对上网操作抓包并进行相关协议分析(实验部分)
    五、实验过程1.安装并启动Wireshark。选择菜单栏上捕获->选项,勾选WLAN网卡。点击Start,进行抓包 Wireshark处于抓包状态中 2.打开浏览器,在地址栏中输入教师指定的web服务器地址。(http://202.113.78.39)为了确保连通性,先ping一下服务器 打开cmd Ping 202.113.78.......
  • 常见算法——自相关的含义及Python、C实现
    常见算法——自相关的含义及C实现一、概念1.自相关概念2.滞后期示例说明:二、自相关的计算步骤:1.确定滞后期(Lag):2.计算平均值:3.计算自相关:三、示例Python自相关计算1.代码2.运行结果四、C语言实现自相关算法1.代码2.运行结果:3.优化4.检测规律波动一、概念1.自相关......
  • 24暑假实习信息、25秋招提前批信息,地信、测绘、遥感、地质相关岗位招聘汇总
    本文整理汇总了地信、测绘、遥感、地质相关岗位招聘助你快速获取一手岗位信息,并且持续更新中.........招聘资料分享https://www.wjx.cn/vm/OaQEBVS.aspx#24年暑期实习信息汇总3s等相关专业招聘信息该岗位信息表,覆盖全国各大省市,招聘岗位主要针对地信、测绘、地质、遥感......
  • 在 PowerShell 中,有多个命令与 IPv6 相关。以下是一些常用的命令和 cmdlet: 管理和配置
    在PowerShell中,有多个命令与IPv6相关。以下是一些常用的命令和cmdlet:获取网络适配器的IPv6地址:powershellCopyCodeGet-NetIPAddress-AddressFamilyIPv6查看所有网络适配器信息:powershellCopyCodeGet-NetAdapter查看特定网络适配器的IPv6地址:powershell......
  • JavaScript 对象的基本操作及相关知识点详解
    在JavaScript中,对象是一种基本的数据结构,以键值对形式保存数据且数据没有顺序,它可以包含多种数据类型的属性和方法。1.创建对象的方法字面量写法: let自定义对象名={}构造函数写法:let自定义对象名=newObject();//字面量写法letperson={};//构造函数......
  • 5号电池的相关科普
    电池串联起来容量会增加吗?当电池串联时,它们的电压会相加,但容量(即电池可以存储的电荷量)并不会改变。这意味着虽然电压提高了,但每个电池的存储能力并没有增强。因此,从容量角度看,串联电池并不会增加整体容量。对于问题中提到的“两组(2V100只串联300Ah)的电池组串联”,我们首先需要......
  • dubbo入坑及相关最佳实践
    dubbo消费者捕获异常最佳实践dubbo一共会抛出两种异常,一个是RpcException,另外一个是RuntimeException。所以消费者在调用dubbo接口要留意捕获一个Exception异常try{returnuserClient.getOrderById(userInfoDTO);}catch(Exceptione){thrownewBizException(......
  • 超链接相关属性:跳转页面、跳转文件、跳转锚点、换成指定应用
    1.跳转页面我这里用绝对网络路径跳转百度、京东说一下img属性值target的含义,值_self是在当前页签跳转,相对的值_blank就是打开新标签跳转注意事项:点击前的超链接字体为蓝色,点击时为红色,点击后的超链接字体为紫色(只限第一次跳转,第一次以后点击前的超链接字体也为紫色,除非刷新......
  • 多智能体协同控制(2):代数图论
    在上一节中,提到了分布式一致性算法的实现与多智能体之间的交流方式密切相关。这一节用图论来揭示不同多智能体之间交流方式的本质差异。图的基本定义我们可以将不同智能体之间的通信方式,抽象出来,称为“通信图”(graph)。如右图所示,舍弃物理意义,将每个智能体抽象成节点(vertex)1,......