不想建树,于是自己琢磨了半天,最终只过了3个测试点,29分,测试点3的1分不知道卡在哪了(哭泣TT)。欢迎各位大佬来吊打我!!
基本思路:红黑树首先是BST,所以它的中序遍历就是先序遍历序列按从小到大排序,在这里是绝对值从小到大。有了先序和中序,就可以对树进行模拟先序遍历了。
根据红黑树的性质,需要对树进行3个判断:
- 根是否是正数;
- 红色节点是否有两个黑色子节点;
- 每条从根到叶的路径上黑色节点数是否相同。
对于1, 只需要判断pre[0]>0即可。
对于2,用func1来判断。红色节点必须有两个黑色孩子节点,只有一个孩子或者任一孩子是红色的都不行。
对于3,用func2来判断。两个func都是先访问根,再递归调用左子树和右子树,因此是模拟的先序遍历。
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
vector<int> pre, in;
bool cmp(int a, int b){
return abs(a)<abs(b);
}
bool func1(int inL, int inR, int preRoot){
if(inL>=inR) return true;
int r=pre[preRoot], i;
for(i=inL;i<=inR;i++)
if(in[i]==r) break;
if(r<0){
if(i==inL||i==inR) return false;
else if(pre[preRoot+1]<0||pre[preRoot+i-inL+1]<0) return false;
}
if(func1(inL, i-1, preRoot+1)) return func1(i+1, inR, preRoot+i-inL+1);
else return false;
}
int func2(int inL, int inR, int preRoot){
int r=pre[preRoot], i;
if(inL>=inR){
if(r>0) return 1;
else return 0;
}
for(i=inL;i<=inR;i++){
if(in[i]==r) break;
}
if(i!=inL&&i!=inR){
if(func2(inL, i-1, preRoot+1)==func2(i+1, inR, preRoot+i-inL+1)){
if(r>0) return func2(inL, i-1, preRoot+1)+1;
else return func2(inL, i-1, preRoot+1);
}
else return i-999;
}
else if(i!=inL) return func2(inL, i-1, preRoot+1)+1;
else return func2(i+1, inR, preRoot+i-inL+1)+1;
}
int main(){
int K, N;
cin>>K;
for(int i=0;i<K;i++){
cin>>N;
pre.resize(N);
in.resize(N);
for(int j=0;j<N;j++){
cin>>pre[j];
in[j]=pre[j];
}
sort(in.begin(), in.end(), cmp);
if(pre[0]>0&&func1(0, N-1, 0)&&(func2(0, N-1, 0)>0)) printf("Yes\n");
else printf("No\n");
}
return 0;
}