点分治小结

最近学了学点分治,毕竟OJ上都搞了个专题了。

引入

以一个点为界限,将一棵树分成若干个子树,当划分到一定规模,就对每个子树分别进行求解

What is 点分治?

我们为了保证时间,所以要使子树大小尽量小。
如何找到最优的点呢?就是重心!

重心

重心是什么?

树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。——百度百科

算法流程

1.求当前树重心。
2.计算答案。
3.走到相邻未操作的节点进行第1步。

求重心

暴力\(O(n)\),找到一个点,使得所连子树的大小的最大值最小。
\(bz\)数组表示其有没有走过(走过就不是当前树了)

void getrt(int x, int fa)
{
	siz[x] = 1; son[x] = 0;
	for (int p = tail[x], v; p; p = e[p].fr)
	{
		v = e[p].v;
		if (v == fa || bz[v]) continue;
		getrt(v, x);
		if (son[x] < siz[v]) son[x] = siz[v];
		siz[x] += siz[v];
	}
	if (son[x] < tot - siz[x]) son[x] = tot - siz[x];
	if (son[x] < son[rt]) rt = x;
}

时间复杂度

可证明为\(O(log^n_2)\)
由于重心有一个性质:
树的重心的每棵子树大小一定小于等于\(n/2\)
所以就可以证明啦。

例题

详见OJ

posted @ 2019-08-03 21:55  jz929  阅读(125)  评论(0编辑  收藏  举报