7-11 笛卡尔树 (25 分)
题目链接:https://pintia.cn/problem-sets/1110382478542622720/problems/1110382589284831241
题目大意:
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大。其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小。给定一棵二叉树,请判断该树是否笛卡尔树。
输入格式:
输入首先给出正整数N(≤1000),为树中结点的个数。随后N行,每行给出一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0~(N-1)顺序编号。若某结点不存在孩子结点,则该位置给出−。
输出格式:
输出YES
如果该树是一棵笛卡尔树;否则输出NO
。
具体思路:对于判断最小堆的时候,递归半段就好了。对于判断二叉搜索树的时候,我们可以直接利用一下搜索二叉树的性质,直接使用中序遍历进行比较,正好符合了递增的性质。所以我们储存一下都有那些树,然后拍一下序,看中序遍历的情况是不是相同的,如果相同则证明是符合情况的。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 # define inf 0x3f3f3f3f 5 const int maxn = 2e5+100; 6 int in[maxn]; 7 struct node 8 { 9 int k1; 10 int k2; 11 int lt; 12 int rt; 13 } q[maxn]; 14 int flag; 15 int sto1[maxn],sto2[maxn]; 16 void dui(int root) 17 { 18 if(!flag) 19 return ; 20 if(q[root].lt!=-1) 21 { 22 if(q[q[root].lt].k2<q[root].k2) 23 { 24 flag=0; 25 return ; 26 } 27 dui(q[root].lt); 28 } 29 if(q[root].rt!=-1) 30 { 31 if(q[q[root].rt].k2<q[root].k2) 32 { 33 flag=0; 34 return ; 35 } 36 dui(q[root].rt); 37 } 38 } 39 int cnt=0; 40 void ceng(int root) 41 { 42 if(root!=-1) 43 { 44 // if() 45 ceng(q[root].lt); 46 sto1[++cnt]=q[root].k1; 47 sto2[cnt]=q[root].k1; 48 ceng(q[root].rt); 49 } 50 } 51 int main() 52 { 53 int n; 54 flag=1; 55 scanf("%d",&n); 56 for(int i=0; i<n; i++) 57 { 58 scanf("%d %d %d %d",&q[i].k1,&q[i].k2,&q[i].lt,&q[i].rt); 59 if(q[i].lt!=-1) 60 in[q[i].lt]++; 61 if(q[i].rt!=-1) 62 in[q[i].rt]++; 63 } 64 int root; 65 for(int i=0; i<n; i++) 66 { 67 if(!in[i]) 68 root=i; 69 } 70 dui(root); 71 ceng(root); 72 int k=1; 73 sort(sto1+1,sto1+cnt+1); 74 for(int i=1; i<=cnt; i++) 75 { 76 if(sto1[i]!=sto2[i]) 77 { 78 k=0; 79 } 80 } 81 // cout<<flag<<" "<<k<<endl; 82 if(flag&&k==1) 83 printf("YES\n"); 84 else 85 printf("NO\n"); 86 return 0; 87 88 }