1. 程式人生 > 實用技巧 >題解 P5566 【[SDOI2008]紅黑樹】

題解 P5566 【[SDOI2008]紅黑樹】

最近在刷平衡樹,看到標題就進來了,沒想到是個dp???看了看,發現可以貪心,於是就有了這篇題解。

分析:

因為紅黑樹本身的性質,所以我們可以通過畫圖來列舉所有情況:


先把每一個節點看成黑色的,通過紅黑樹性質來把一些結點變成紅色的。

  • \(case1:\)

如圖:

最虧的一種情況,兩個黑色節點沒變出來一個紅色節點。

  • \(case2:\)

如圖:

三個黑色節點變成一個紅色節點,有點浪費。

  • \(case3:\)

如圖:

此時四個黑色節點變成兩個紅色節點,黑色節點的利用率最大。


所以,貪心就很明確了。

\(\text{code:}\)

#include "cstdio"
int n, ans, k;
int main()
{
	scanf("%d", &n);
	k = n + 1;
	while (k > 1)
	{
		ans += k & 1;
		k >>= 1;
	}
	printf("%d\n", ans);
	k = n + 1;
	ans = 0;
	while (k > 1)
	{
		if (k == 2)
			ans++, k--;
		else if ((k & 3) == 1)
			ans += ((k >> 2) << 1) - 1, k >>= 2, k++;
		else if ((k & 3) == 2)
			ans += ((k >> 2) << 1), k >>= 2, k++;
		else if ((k & 3) == 3)
			ans += ((k >> 2) << 1) + 1, k >>= 2, k++;
		else
			ans += (k >> 1), k >>= 2;
	}
	printf("%d", ans);
	return 0;
}

關於DP

自己想了一種方法,不過好像有億點點慢。

以最小值為例:

\(R_{(i,j)}\) 表示 \(i\) 個結點,黑高度為 \(j\) 的紅根樹中紅色結點最小值;

\(B_{(i,j)}\) 表示 \(i\) 個結點,黑高度為 \(j\) 的黑根樹中紅色結點最小值。

\(\therefore R_{(i,j)}=\min\left({R_{(i,j)},B_{(k,j-1)}+B_{(i-k-1,j-1)}+1}\right)\quad(i\leq k\leq i-2)\)

\(\therefore B_{(i,j)}=\min\left({B_{(k,j-1)},B_{(i-k-1,j-1)},R_{(k,j)}+R_{(i-k-1,j)},R_{(k,j)}+B_{(i-k-1,j-1)}}\right)\quad(i\leq k\leq i-2)\)


程式碼就不放了,貪心它不香嗎?