Peter算法小课堂—树链剖分(1)

我们先引入一些关于“重链剖分”的概念

定义

重儿子:子树节点最多的儿子称之为“重儿子”。若有两个儿子子树大小相同,约定选取编号较小的儿子。

如图,请你写出1、3、4的重儿子

由上面的定义,我们知道1、3、4的重儿子分别为3、2、5

我们用一个数组son[]存u的重儿子编号,按照上图,我们可以列出这张表

重边:每个节点与他的重儿子之间的连边为重边。

那么,我们就把这棵树划为了这样子

重链:将相邻的重边连接起来,就成了一条重链。

就变成了这样子

那么,我们用一个数组top[]来存u所在重链的链头(最高点)。

由上图,可以写出top[]

同样,我们也可以写出下面这棵树的top[]

由前面的定义,我们可以这样划分

所以我们可以写出

算法

我们一共要跑两次dfs,

代码自己写一些

void dfs_son(int u,int fa){
	sz[u]=1;
	son[u]=0;
	for(int i=0;i<=to[u].size();i++){
		int v=to[u][i];
		if(v==fa) continue;
		dfs_son(v,u);
		sz[u]+=sz[v];
		if(sz[son[u]]<sz[v]||sz[son[u]]==sz[v]&&v<son[u]){
			son[u]=v;
		}
	}
}
void dfs_top(int u,int fa){
	if(son[fa]==u) top[u]==fa;
	else top[u]==u;
	for(int i=0;i<=to[u].size();i++){
		int v=to[u][i];
		if(v==fa) continue;
		dfs_top(v,u);
	}
}

2562

题目描述:

已知一棵二叉树共n个节点,编号1到n,根节点是1号。请对该树进行深度优先搜索(DFS),搜索时优先选重儿子访问,输出DFS序列以及每个节点的DFN。

我们一般称这种dfs叫做重儿子先行dfs,也叫SFS序列化(size first search)。这里我们比上一道题要多令两个数组:dfn[]和id[]

然后多加一个时间戳timer

void dfs_son(int u,int fa){
	sz[u]=1;
	son[u]=0;
	for(int i=0;i<=to[u].size();i++){
		int v=to[u][i];
		if(v==fa) continue;
		dfs_son(v,u);
		sz[u]+=sz[v];
		if(sz[son[u]]<sz[v]||sz[son[u]]==sz[v]&&v<son[u]){
			son[u]=v;
		}
	}
}
void dfs_top(int u,int fa){
	++timer;
	dfn[u]=timer;
	id[timer]=u;
	if(son[fa]==u) top[u]==fa;
	else top[u]==u;
	for(int i=0;i<=to[u].size();i++){
		int v=to[u][i];
		if(v==fa) continue;
		dfs_top(v,u);
	}
}

2563

题目描述:

已知一棵树共n个节点,编号1到n,根节点是1号。现在共有m个关于“路径剖分”的问询,每个问询形式为:对于节点x和y,从x到y的路径共经过几条不同的重链。

看到这题,首先应该想到的是LCA,交替爬树

首先,若top[u]==top[v],答案为1,那是显然的

若d[top[u]]<d[top[v]],将v跳到p[top[v]]上,直到u、v在同一条链上为止。

那么,我们写一个爬树函数

int query(int u,int v){
	int cnt=1;
	while(top[u]!=top[v]){
		if(d[top[u]]<d[top[v]])
			v=p[top[v]];
		else u=p[top[u]];
		++cnt;
	}
	return cnt;
}

最后,我们来到我们的性质讨论环节

性质讨论

重链数=叶子数

证明:只需说明重链数与叶子数的双射(一一对应)即可

树的重心一定在根出发的重链上

证明:假设重心G不在链上,则将G改为G的邻居G',使G'更靠近G,取G'为根时,最大子树变小了。

任一点v到根路径上轻边数不超过log(n)

证明:

任一点v到根路径上重边数不超过log(n)

证明:

任一点u到v路径上重边数不超过2log(n)

证明:相当于把LCA(u,v)当作根

彩蛋

最近看到了一道牛掰数学题

是证明x^{x}\geq e^{x-1},满级证明:

其中用到了不等式e^{x}\geq x+1,这很好证

(这跟编程无关)

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值