1147 Heaps
抓住完全二叉树的性质:某个节点编号为
i
d
id
id,左儿子为
2
∗
i
d
2*id
2∗id,右儿子为
2
∗
i
d
+
1
2*id+1
2∗id+1
利用这条性质可以精准定位到节点的左右儿子
之后正常进行大小根堆的判断和后序遍历即可
Tip
所有树上的操作,最关键的是确定结构,即确定左右儿子
换句话说,只要我们能够确定儿子,就可以对树直接进行操作,建树就变得无关紧要了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N = 1010;
int t[N];
int ans[N], cnt = 0;
int n;
void dfs(int i) {
int lc = i * 2;
int rc = i * 2 + 1;
if (lc <= n) dfs(lc);
if (rc <= n) dfs(rc);
ans[++cnt] = t[i];
}
int main()
{
int T;
scanf("%d%d", &T, &n);
while (T--) {
for (int i = 1; i <= n; ++i)
scanf("%d",&t[i]);
int flag = 0;
cnt = 0;
for (int i = 1; 2 * i <= n; ++i) {
if (2 * i + 1 <= n) {
if (t[i] >= t[i * 2] && t[i] >= t[i * 2 + 1]) {
if (flag >= 0) flag = 1;
else {
flag = 0;
break;
}
}
else if (t[i] <= t[i * 2] && t[i] <= t[i * 2 + 1]) {
if (flag <= 0) flag = -1;
else {
flag = 0;
break;
}
}
else {
flag = 0;
break;
}
}
else {
if (t[i] >= t[i * 2]) {
if (flag >= 0) flag = 1;
else {
flag = 0;
break;
}
}
else if (t[i] <= t[i * 2]) {
if (flag <= 0) flag = -1;
else {
flag = 0;
break;
}
}
else {
flag = 0;
break;
}
}
}
if (flag == 0) printf("Not Heap\n");
else if (flag > 0) printf("Max Heap\n");
else printf("Min Heap\n");
dfs(1);
for (int i = 1; i <= n; ++i) {
printf("%d", ans[i]);
if (i < n) printf(" ");
}
printf("\n");
}
return 0;
}
1115 Counting Nodes in a Binary Search Tree
二叉搜索树(不带旋转操作)的建立,还是比较容易的
对于每个节点记录深度deep,最后输出时按照deep统计一下即可
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N = 1010;
int n, cnt = 0;
int mxdeep;
struct node {
int x;
int lc;
int rc;
int deep;
};
node T[N];
void insert(int i, int x) {
if (x <= T[i].x) {
if (T[i].lc != -1) insert(T[i].lc, x);
else {
T[i].lc = ++cnt;
T[cnt].x = x;
T[cnt].lc = T[cnt].rc = -1;
T[cnt].deep = T[i].deep + 1;
mxdeep = max(mxdeep, T[cnt].deep);
return;
}
}
else {
if (T[i].rc != -1) insert(T[i].rc, x);
else {
T[i].rc = ++cnt;
T[cnt].x = x;
T[cnt].lc = T[cnt].rc = -1;
T[cnt].deep = T[i].deep + 1;
mxdeep = max(mxdeep, T[cnt].deep);
return;
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int x;
scanf("%d", &x);
if (i == 1) {
T[1].x = x;
T[1].lc = T[1].rc = -1;
T[1].deep = 1;
mxdeep = 1;
cnt = 1;
}
else insert(1,x);
}
int n1 = 0;
int n2 = 0;
for (int i = 1; i <= cnt; ++i) {
if (T[i].deep == mxdeep) n1++;
if (T[i].deep == mxdeep - 1) n2++;
}
printf("%d + %d = %d", n1, n2, n1 + n2);
return 0;
}
1167 Cartesian Tree
不要被题目描述吓住了
题目给出了一个小根二叉树的中序遍历
根节点必然是子树中序遍历中最小的那个节点
确定了根节点,自然就划分出左右子树,进行递归建树即可
最后bfs输出层次遍历即可
Tip
根据序列建树的关键是划分左右子树
前序+中序,后序+中序,前序+二叉搜索树,中序+小(大)根堆
以上情况都可以确定唯一树结构
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N = 40;
int n, cnt = 1;
int a[N];
struct node {
int num;
int lc;
int rc;
};
node T[N];
void build(int x,int l,int r) {
int index = l;
for (int i = l; i <= r; ++i)
if (a[i] < a[index]) index = i;
T[x].num = a[index];
T[x].lc = T[x].rc = -1;
if (index > l) {
T[x].lc = ++cnt;
build(cnt, l, index - 1);
}
if (index < r) {
T[x].rc = ++cnt;
build(cnt, index + 1, r);
}
}
int Q[N * 2];
void bfs() {
int tou = 0;
int wei = 0;
Q[++wei] = 1;
while (tou < wei) {
int index = Q[++tou];
if (T[index].lc != -1) Q[++wei] = T[index].lc;
if (T[index].rc != -1) Q[++wei] = T[index].rc;
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
build(1,1,n);
bfs();
for (int i = 1; i <= n; ++i) {
printf("%d", T[Q[i]].num);
if (i < n) printf(" ");
}
return 0;
}