1、题面:
https://pintia.cn/problem-sets/994805342720868352/problems/1038430130011897856
2、题意:
给出树的中序、前序,然后询问u,v的lca
3、正解:
1、不建树,直接递归查找 https://blog.csdn.net/liuchuo/article/details/82560863
2、建树,并查集暴力lca,需要离散化
4、错误:
用建树写的,然后被离散搞蒙了
5、思维:
建树实际上不需要保存左右节点,因为lca只要知道是不是父子即可
开始担心暴力会不会T,事实证明PAT时间还是挺宽裕的
题目里说是distinct 数字,所以会有负数之类的数字出现,如果用数组做并查集,只能离散化
6、代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int pre[N]={0},mid[N]={0},fa[N]={0},n,m,chk[N];
void work(int l,int r,int &p,int f){
if(l>r || p>n) return ;
p++;
int i;
for(i=l;i<=r;i++)
if(mid[i] == pre[p]) break;
if(i==r+1){
p--;return ;
}
fa[ pre[p] ] = f;
work(1,i-1,p,mid[i]);
work(i+1,r,p,mid[i]);
}
int lca(int a,int b){//并查集暴力lca
memset(chk,0,sizeof(chk));
while(fa[a]!=a) chk[a]=1,a=fa[a];
while(fa[b]!=b){
if(chk[b]==1) return b;
b = fa[b];
}
}
struct node{
int id,val;
node(){;}
node(int a,int b){id = a; val = b;}
bool operator<(const node &b)const{
return val < b.val;
}
}num[N];
int main(){
int a,b,c=0;
cin>>m>>n;
for(int i=1;i<=n;i++) scanf("%d",&num[i].val),num[i].id = i;
sort(num+1,num+1+n);//离散化
for(int i=1;i<=n;i++) mid[ num[i].id ] = i;
for(int i=1;i<=n;i++) scanf("%d",&num[i].val),num[i].id = i;
sort(num+1,num+1+n);//离散化
for(int i=1;i<=n;i++) pre[ num[i].id ] = i;
work(1,n,c,pre[1]);
for(int i=1;i<=m;i++){
int t = 0,A,B,T;
scanf("%d %d",&a,&b);
A = lower_bound(num+1,num+1+n,node(0,a))-num;
B = lower_bound(num+1,num+1+n,node(0,b))-num;
if(num[A].val!=a) t++;
if(num[B].val!=b) t++;
if(t==2){
printf("ERROR: %d and %d are not found.\n",a,b);
}else if(t==1){
printf("ERROR: %d is not found.\n",num[A].val!=a?a:b);
}else{
T = lca(A,B);//T->离散化后的值
t = num[T].val;
if(t == a || t==b){
printf("%d is an ancestor of %d.\n",t==a?a:b,t==a?b:a);
}else{
printf("LCA of %d and %d is %d.\n",a,b,t);
}
}
}
}