题意:给你一棵树的先序遍历,问你是不是一颗红黑树。
思路:红黑树的定义:
1、 每个结点的颜色只能是红色或黑色。
2、 根结点是黑色的。
3、 每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;
如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。
4、 如果一个结点是红的,则它的两个儿子都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
5、 对于每个结点来说,从该结点到其子孙叶结点的所有路径上包含相同数目的黑结点。
因为红黑树也是二叉搜索树,所以根据先序遍历就能得到这棵树,2、4是很好判断的。5的话可以以根节点dfs一遍整棵树,每次返回节点到叶子的黑色个数,判断左右孩子的黑色个数是否相等就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const int maxn = 1e4+5;
int a[maxn], n, cur, tmp;
int lch[maxn], rch[maxn], val[maxn];
bool ok;
void Insert(int root, int x)
{
if(abs(x) <= abs(val[root]))
{
if(lch[root] == -1)
{
lch[root] = cur;
val[cur] = x;
cur++;
return ;
}
else Insert(lch[root], x);
}
else
{
if(rch[root] == -1)
{
rch[root] = cur;
val[cur] = x;
cur++;
return ;
}
else Insert(rch[root], x);
}
}
bool judge()
{
if(val[0] < 0) return 0;
queue<int> q;
q.push(0);
while(!q.empty())
{
int u = q.front(); q.pop();
if(val[u] < 0)
{
if(lch[u] != -1 && val[lch[u]] < 0) return 0;
if(rch[u] != -1 && val[rch[u]] < 0) return 0;
}
if(lch[u] != -1) q.push(lch[u]);
if(rch[u] != -1) q.push(rch[u]);
}
return 1;
}
int judge2(int root)
{
if(!ok) return -1;
if(root == -1) return 1;
int num1 = judge2(lch[root]);
int num2 = judge2(rch[root]);
if(num1 != num2) ok = 0;
return num1+(val[root]>0);
}
int main(void)
{
int _;
cin >> _;
while(_--)
{
cur = 0;
memset(lch, -1, sizeof(lch));
memset(rch, -1, sizeof(rch));
scanf("%d", &n);
scanf("%d", &a[1]);
val[cur++] = a[1];
for(int i = 2; i <= n; i++)
scanf("%d", &a[i]), Insert(0, a[i]);
ok = judge();
judge2(0);
puts(ok ? "Yes" : "No");
}
return 0;
}