ABC255F
作者:互联网
想不到我一个pj2=的人也能做出F题啊!
注:我以前看不懂EF的Editorial,所以从没做出来过……
题面
给你一棵二叉树的前序和中序遍历,重构这颗二叉树。(根节点为1)
Part1 确定根节点和左右子树的所有节点
谁都知道一颗二叉树的根节点就是它的前序遍历的第一项。
那么确定左右子树的内容就交给中序遍历了。
$ pre_1 $ $ pre_2 $ $ pre_3 $ 根节点: $ pre_1 $
$ in_1 $ $ in_2 $ $ in_3 $ 发现 $ pre_1 = in_2 $,可以确定左子树与右子树。
Part2 确定左子树根节点和左右子树的所有节点
请重新阅读 Part1。
Part3 Error!
如果我们确定到的根节点不在递归范围之内,那就对不住了!
代码
#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <set>
#include <map>
#include <utility>
#include <queue>
#include <vector>
#include <bitset>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define maxn 200005
int L[maxn], R[maxn];
int pre[maxn], in[maxn], inv[maxn];
bool solve(int preL, int preR, int inL, int inR) { // 递归范围:前序preL ~ preR,中序inL ~ inR
int Rt = pre[preL], invRt = inv[Rt]; // 根和根在中序里的位置
if (inL > invRt || invRt > inR) { // Part3
return false;
}
if (invRt - inL > 0) {
L[Rt] = pre[preL + 1];
if (!solve(preL + 1, preL + invRt - inL, inL, invRt - 1)) { // Part2,长度为invRt - inL
return false;
}
}
if (inR - invRt > 0) {
R[Rt] = pre[preL + invRt - inL + 1];
if (!solve(preL + invRt - inL + 1, preR, invRt + 1, inR)) { // Part2 Again
return false;
}
}
return true;
}
int main() {
memset(L, -1, sizeof(L));
memset(R, -1, sizeof(R));
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &pre[i]);
pre[i]--;
}
for (int i = 0; i < n; i++) {
scanf("%d", &in[i]);
in[i]--;
inv[in[i]] = i; // 预处理出节点在中序里的位置
}
if (pre[0] != 0 || !solve(0, n - 1, 0, n - 1)) { // Part1 + Part3
printf("%d", -1); // Part3
} else {
for (int i = 0; i < n; i++) {
printf("%d %d\n", L[i] + 1, R[i] + 1); // 注意!我用的是0 ~ n - 1,题目是1 ~ n!
}
}
return 0;
}
后记
马上要到暑假啦 ~
暑假会一周2 ~ 3更!
P.S. 祝大家今晚的Atcoder RP++!
都看到这里了,还不点赞推荐加关注 ~
不白嫖,从我做起!
标签:pre,preL,int,invRt,inL,ABC255F,include 来源: https://www.cnblogs.com/AProblemSolver/p/16388056.html