受柳神启发,其实不用建树也可以。这是仿照《算法笔记》的代码风格所写。
核心思想:建树后,利用map<int,int> pos保存中序树每个结点对应在数组中的位置,找到根节点就可以判断出其左右子树。
#include <bits/stdc++.h>
using namespace std;
struct node{
int data;
vector<int> child;
node* lchild;
node* rchild;
node(int d){
this->data = d;
this->lchild = this->rchild = nullptr;
}
};
int m,n;
vector<int> pre,in;
map<int,int> pos; //保存中序树每个结点对应的数组下标
node* create(int preL,int preR,int inL,int inR){
if(preL>preR){
return nullptr;
}
node* root = new node(pre[preL]);
int k;
for(k=inL;k<=inR;k++){
if(in[k]==pre[preL])
break;
}
int numleft = k-inL;
root->lchild = create(preL+1,preL+numleft,inL,k-1);
root->rchild = create(preL+numleft+1,preR,k+1,inR);
return root;
}
void LCA(node* s,int a,int b){
if(s==nullptr)return;
int inRoot = pos[s->data];
int inA = pos[a];
int inB = pos[b];
if((inA>inRoot&&inB<inRoot)||(inA<inRoot&&inB>inRoot)) //a、b分别在左右子树
printf("LCA of %d and %d is %d.\n",a,b,s->data);
else if(inA<inRoot&&inB<inRoot){ //a、b都在左子树
LCA(s->lchild,a,b);
}
else if(inA>inRoot&&inB>inRoot){ //a、b都在右子树
LCA(s->rchild,a,b);
}
else if(s->data==a){ //a等于此时根结点对应的值,a就是祖先
printf("%d is an ancestor of %d\n",a,b);
}
else if(s->data==b){ //b等于此时根结点对应的值,b就是祖先
printf("%d is an ancestor of %d\n",b,a);
}
}
int main(){
cin>>m>>n;
pre.resize(n+1);
in.resize(n+1);
for(int i=0;i<n;i++){
cin>>in[i];
pos[in[i]] = i;
}
for(int i=0;i<n;i++){
cin>>pre[i];
}
node* root = create(0,n-1,0,n-1);
int a,b;
for(int i=0;i<m;i++){
cin>>a>>b;
bool find1 = true;
bool find2 = true;
for(int i=0;i<n;i++){
if(a==in[i])
find1 = false;
if(b==in[i])
find2 = false;
}
if(find1&&find2){
printf("ERROR: %d and %d are not found.\n",a,b);
}
else if(find1||find2){
printf("ERROR: %d and %d are not found.\n",find1?(a,b):(b,a));
}
else{
LCA(root,a,b);
}
}
return 0;
}