点分治小结
最近学了学点分治,毕竟OJ上都搞了个专题了。
引入
以一个点为界限,将一棵树分成若干个子树,当划分到一定规模,就对每个子树分别进行求解
我们为了保证时间,所以要使子树大小尽量小。
如何找到最优的点呢?就是重心!
重心
重心是什么?
树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。——百度百科
算法流程
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
转载需注明出处。