散落星河的记忆🌠
Published on 2017-09-02 11:31 in 暂未分类 with 散落星河的记忆🌠

[BZOJ 3227] [SDOI 2008] 红黑树(tree)

Description

红黑树是一类特殊的二叉搜索树,其中每个结点被染成红色或黑色。若将二叉搜索树结点中的空指针看作是指向一个空结点,则称这类空结点为二叉搜索树的前端结点。并规定所有前端结点的高度为-1。
  
一棵红黑树是满足下面“红黑性质”的染色二叉搜索树:

  (1) 每个结点被染成红色或黑色;
  (2) 每个前端结点为黑色结点;
  (3) 任一红结点的子结点均为黑结点;
  (4) 在从任一结点到其子孙前端结点的所有路径上具有相同的黑结点数。

从红黑树中任一结点 \(x\) 出发(不包括结点 \(x\)),到达一个前端结点的任意一条路径上的黑结点个数称为结点 \(x\) 的黑高度,记作 \(bh(x)\)。红黑树的黑高度定义为其根结点的黑高度。
  
给定正整数 \(N\),试设计一个算法,计算出在所有含有 \(N\) 个结点的红黑树中,红色内结点个数的最小值和最大值。

Input

  输入共一个数 \(N\)

Output

  输出共两行。
  第一行为红色内结点个数的最小值,第二行为最大值。

Sample Input

8

Sample Output

1
4

HINT

对于 100% 的数据,\(1≤N≤5000\)

Solution

\(f[i][j][0/1]\) 表示节点数为 \(i\) 的子树,该树的黑高度为 \(j\),根节点颜色为红/黑,容易想出 \(n^3\) 的转移方程:

\[f[x][h][0]=\min\{f[y][h][1]+f[x-y-1][h][1]\}+1\\ f[x][h][1]=\min\{f[y][h-1][0/1]+f[x-y-1][h-1][0/1]\} \]

有个性质,黑高度是 \(O(\log n)\) 级别的,那么复杂度就可以降为 \(O(n^2\log n)\)

这里还有一种 \(O(\log n)\) 的贪心做法:

一棵 \(n\) 个节点的红黑树,前端节点的个数一定是 \(n+1\) 个,证明考虑先证出一条链的情况,然后无论怎么移动节点都不变。

于是就相当于将 \(n+1\) 个黑点合并成一个根节点,每次我们将一部分黑节点合并成一个黑节点,无非就这三种情况:

(图片来自这里

这三棵树的黑高度都是相同的,可以逐层合并,对于最小值,我们就两个两个合并,最大值就四个四个合并。具体见代码。

注意代码中加 \(!!!\) 的那一行,由于 \(2/4*2=0\),因此要单独判断。

Code

#include <cstdio>

int main() {
	int n, m, ans = 0;
	scanf("%d", &n), m = n + 1;
	while (m > 1) ans += m & 1, m >>= 1;
	printf("%d\n", ans), m = n + 1, ans = 0;
	while (m > 1) {
		if (m == 2) ++ans, --m; //!!!
		else if ((m & 3) == 1) ans += ((m >> 2) << 1) - 1, m = (m >> 2) + 1;
		else if ((m & 3) == 2) ans += (m >> 2) << 1, m = (m >> 2) + 1;
		else if ((m & 3) == 3) ans += ((m >> 2) << 1) + 1, m = (m >> 2) + 1;
		else ans += m >> 1, m >>= 2;
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2019-03-12 07:06  散落星河的记忆🌠  阅读(257)  评论(0编辑  收藏  举报