1151 LCA in a Binary Tree (30 point(s))

本文深入解析了二叉树中寻找两个节点的最低公共祖先(LCA)的算法,提供了详细的实现步骤,包括根据先序和中序遍历序列重建二叉树、节点存储策略以及通过回溯查找LCA的方法。

1151 LCA in a Binary Tree (30 point(s))

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.

Output Specification:

For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..

Sample Input:

6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99

Sample Output:

LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

 LCA(最低公共祖先结点)。

注意点:

1. 结点的静态存储。

2. 树的重建,获得所在层次和父亲结点。

思路:

1. 先根据先序遍历和中序遍历重建树,注意保存结点的父亲结点下标所在层次。树的存储采取静态方式,方便通过结点的值找到结点。

2. 然后根据根据给出数对的数据找到这两个结点。

3. 注意到每一个非根结点的父亲结点是唯一的。将较低的结点向上回溯,直到所在的层次一样,如果此时就相等的,说明较高的结点是较低结点的祖先;否则同时回溯,直到结点相同。

参考链接:https://blog.youkuaiyun.com/richenyunqi/article/details/79839484

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int M,N;
const int MAX = 1e4+7;
struct Node{
	int data;int level;int father;//由于需要回溯,保存结点的父亲结点的下标(前序遍历的位置)和层次 
	Node(int d=0,int l=0,int f=-1):data(d),level(l),father(f){} 
};
Node pre[MAX];//结点静态存储 
int in[MAX];
void createTree(int root,int left,int right,int father,int level){
	//根据前序遍历的root位置和中序遍历的left和right的区间重建树 
	if(left>right) return;
	pre[root] =  Node(pre[root].data,level,father);
	int index = left;
	while(pre[root].data!=in[index]) index++;
	createTree(root+1,left,index-1,root,level+1);
	createTree(root+1+index-left,index+1,right,root,level+1);
}
int main(void){
	cin>>M>>N;
	for(int i=0;i<N;i++) cin>>in[i];
	for(int i=0;i<N;i++) cin>>pre[i].data;
	createTree(0,0,N-1,-1,0);
	int a,b;
	for(int i=0;i<M;i++){
		cin>>a>>b;
		int ai=N;int bi=N;
		for(int i=0;i<N;i++){//根据数据查询结点的下标 
			if(a==pre[i].data) ai = i;
			if(b==pre[i].data) bi = i;
		}
		if(ai==N&&bi==N) printf("ERROR: %d and %d are not found.\n",a,b);
		else if(ai==N&&bi!=N) printf("ERROR: %d is not found.\n",a);
		else if(ai!=N&&bi==N) printf("ERROR: %d is not found.\n",b);
		else{
			bool deeper = true;//Node a is deeper;
			if(pre[ai].level<pre[bi].level){
				deeper = false;
				swap(ai,bi);
			}
			while(pre[ai].level!=pre[bi].level) ai = pre[ai].father;//使得两个结点深度相同 
			if(ai==bi){
				printf("%d is an ancestor of %d.\n",(deeper?b:a),(deeper?a:b));//如果此时两个结点到了同一层 
			}
			else{
				while(ai!=bi){//否则同时向上回溯 
					ai = pre[ai].father;
					bi = pre[bi].father;
				}
				printf("LCA of %d and %d is %d.\n",a,b,pre[ai].data);
			}
		}
	}
	return 0;
}

 

/* In this ordinary autumn We drift away without a sound Stepping out of autumn’s hush */ import java.io.IOException; import java.io.InputStream; import java.util.*; public class Main{ static final long mod=1000000007; static final FastScanner in = new FastScanner(); static final StringBuilder out = new StringBuilder(); public static void main(String[] args) throws Exception { run(); System.out.print(out.toString()); } static void run() { try { int t = 1; while (t-- > 0) { solve(); } } catch (Exception e) { e.printStackTrace(); } } static void solve() throws Exception { int n=in.nextInt(); int a=in.nextInt(); int b=in.nextInt(); int ans=0; for(int i=0;i<n;i++) { if(i>=a&&n-i-1<=b) { ans++; } } out.append(ans); } // ================= FastScanner ================= static final class FastScanner { private final InputStream in = System.in; private final byte[] buffer = new byte[1 << 16]; private int ptr = 0, len = 0; private int read() throws IOException { if (ptr >= len) { len = in.read(buffer); ptr = 0; if (len <= 0) return -1; } return buffer[ptr++]; } private int skip() throws IOException { int c; while ((c = read()) <= ' ' && c >= 0) ; return c; } public String next() throws IOException { int c = skip(); if (c < 0) return null; StringBuilder sb = new StringBuilder(); for (; c > ' '; c = read()) sb.append((char) c); return sb.toString(); } public int nextInt() throws IOException { int c = skip(); if (c < 0) return Integer.MIN_VALUE; int sign = 1; if (c == '-') { sign = -1; c = read(); } int val = 0; for (; c > ' '; c = read()) val = val * 10 + (c - '0'); return val * sign; } public long nextLong() throws IOException { int c = skip(); if (c < 0) return Long.MIN_VALUE; long sign = 1; if (c == '-') { sign = -1; c = read(); } long val = 0; for (; c > ' '; c = read()) val = val * 10 + (c - '0'); return val * sign; } public double nextDouble() throws IOException { String s = next(); return s == null ? Double.NaN : Double.parseDouble(s); } public String nextLine() throws IOException { StringBuilder sb = new StringBuilder(); int c = read(); if (c < 0) return null; while (c == '\r' || c == '\n') { c = read(); if (c < 0) return null; } for (; c >= 0 && c != '\n' && c != '\r'; c = read()) sb.append((char) c); return sb.toString(); } } // -------- 并查集(DSU) -------- static class DSU { int[] p, r; public DSU(int n) { p = new int[n]; r = new int[n]; for (int i = 0; i < n; i++) p[i] = i; } int find(int x) { return p[x] == x ? x : (p[x] = find(p[x])); } boolean union(int a, int b) { a = find(a); b = find(b); if (a == b) return false; if (r[a] < r[b]) { int t = a; a = b; b = t; } p[b] = a; if (r[a] == r[b]) r[a]++; return true; } } // -------- Fenwick / Binary Indexed Tree (1-indexed) -------- static class Fenwick { int n; long[] f; Fenwick(int n) { this.n = n; f = new long[n + 1]; } void add(int i, long delta) { for (; i <= n; i += i & -i) f[i] += delta; } long sum(int i) { long s = 0; for (; i > 0; i -= i & -i) s += f[i]; return s; } long sum(int l, int r) { if (r < l) return 0; return sum(r) - sum(l - 1); } } // -------- 迭代线段树(区间和,点更新) -------- static class SegTree { int n; long[] t; SegTree(int n) { this.n = 1; while (this.n < n) this.n <<= 1; t = new long[this.n << 1]; } void set(int pos, long val) { // point assign int i = pos + n; t[i] = val; for (i >>= 1; i > 0; i >>= 1) t[i] = t[i << 1] + t[i << 1 | 1]; } void add(int pos, long delta) { int i = pos + n; t[i] += delta; for (i >>= 1; i > 0; i >>= 1) t[i] = t[i << 1] + t[i << 1 | 1]; } long query(int l, int r) { // inclusive [l,r] l += n; r += n; long res = 0; while (l <= r) { if ((l & 1) == 1) res += t[l++]; if ((r & 1) == 0) res += t[r--]; l >>= 1; r >>= 1; } return res; } } // -------- Sparse Table (RMQ) -------- static class SparseTable { int n, LOG; int[][] st; // min int[] lg; SparseTable(int[] a) { n = a.length; LOG = 32 - Integer.numberOfLeadingZeros(n); st = new int[LOG][n]; lg = new int[n + 1]; for (int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1; System.arraycopy(a, 0, st[0], 0, n); for (int k = 1; k < LOG; k++) for (int i = 0; i + (1 << k) <= n; i++) st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); } int query(int l, int r) { int k = lg[r - l + 1]; return Math.min(st[k][l], st[k][r - (1 << k) + 1]); } } // -------- Dijkstra(邻接表) -------- static class Dijkstra { static long[] dijkstra(int n, ArrayList<int[]>[] g, int src) { long[] dist = new long[n]; Arrays.fill(dist, Long.MAX_VALUE); PriorityQueue<long[]> pq = new PriorityQueue<>(Comparator.comparingLong(a -> a[0])); dist[src] = 0; pq.add(new long[]{0, src}); while (!pq.isEmpty()) { long[] cur = pq.poll(); long du = cur[0]; int u = (int) cur[1]; if (du != dist[u]) continue; for (int[] e : g[u]) { int v = e[0]; int w = e[1]; if (dist[v] > du + w) { dist[v] = du + w; pq.add(new long[]{dist[v], v}); } } } return dist; } } // -------- Dinic 最大流(邻接表 + 边对象) -------- static class Dinic { static class Edge { int v; int rev; int cap; Edge(int v, int rev, int cap){this.v=v;this.rev=rev;this.cap=cap;} } int n, s, t; ArrayList<Edge>[] g; int[] level, it; @SuppressWarnings("unchecked") Dinic(int n, int s, int t) { this.n = n; this.s = s; this.t = t; g = new ArrayList[n]; for (int i = 0; i < n; i++) g[i] = new ArrayList<>(); level = new int[n]; it = new int[n]; } void addEdge(int u, int v, int cap){ g[u].add(new Edge(v, g[v].size(), cap)); g[v].add(new Edge(u, g[u].size() - 1, 0)); } boolean bfs() { Arrays.fill(level, -1); Deque<Integer> dq = new ArrayDeque<>(); dq.add(s); level[s] = 0; while (!dq.isEmpty()) { int u = dq.poll(); for (Edge e : g[u]) if (e.cap > 0 && level[e.v] < 0) { level[e.v] = level[u] + 1; dq.add(e.v); } } return level[t] >= 0; } int dfs(int u, int f) { if (u == t) return f; for (int i = it[u]; i < g[u].size(); i++, it[u]++) { Edge e = g[u].get(i); if (e.cap > 0 && level[e.v] == level[u] + 1) { int ret = dfs(e.v, Math.min(f, e.cap)); if (ret > 0) { e.cap -= ret; g[e.v].get(e.rev).cap += ret; return ret; } } } return 0; } long maxFlow() { long flow = 0; while (bfs()) { Arrays.fill(it, 0); int f; while ((f = dfs(s, Integer.MAX_VALUE)) > 0) flow += f; } return flow; } } // -------- 组合数(阶乘 / 逆元) -------- static class Comb { int MAX; long MOD; long[] fact, ifact; Comb(int max, long mod) { MAX = max; MOD = mod; fact = new long[MAX + 1]; ifact = new long[MAX + 1]; fact[0] = 1; for (int i = 1; i <= MAX; i++) fact[i] = (fact[i - 1] * i) % MOD; ifact[MAX] = modInv(fact[MAX], MOD); for (int i = MAX; i > 0; i--) ifact[i - 1] = (ifact[i] * i) % MOD; } public long powInv(long powMod, long mod2) { // TODO Auto-generated method stub return 0; } long nCk(int n, int k) { if (k < 0 || k > n) return 0; return (((fact[n] * ifact[k]) % MOD) * ifact[n - k]) % MOD; } long modPow(long a, long e){ long r = 1; a %= MOD; while (e > 0) { if ((e & 1) == 1) r = (r * a) % MOD; a = (a * a) % MOD; e >>= 1; } return r; } long modInv(long a, long mod){ return modPow(a, mod - 2); } } // ================= 极简快速堆(用于 Dijkstra) ================= // 使用 long 打包 (distance << 32) | node;避免对象分配 static final class FastHeap { long[] a; int size; FastHeap(int cap){ a = new long[cap]; size = 0; } void push(long x){ if (size >= a.length) a = Arrays.copyOf(a, a.length << 1); a[size++] = x; siftUp(size - 1); } long pop(){ long r = a[0]; a[0] = a[--size]; siftDown(0); return r; } boolean isEmpty(){ return size == 0; } void siftUp(int i){ long v = a[i]; while (i > 0){ int p = (i - 1) >> 1; if (a[p] <= v) break; a[i] = a[p]; i = p; } a[i] = v; } void siftDown(int i){ long v = a[i]; int n = size; while (true){ int l = i << 1 | 1; if (l >= n) break; int r = l + 1; int j = (r < n && a[r] < a[l]) ? r : l; if (a[j] >= v) break; a[i] = a[j]; i = j; } a[i] = v; } } // ================= IntDeque(双端队列,array-based) ================= static final class IntDeque { int[] a; int head, tail, n; IntDeque(int cap){ n = 1; while (n < cap) n <<= 1; a = new int[n]; head = tail = 0; } void addLast(int x){ a[tail++] = x; if (tail == n) tail = 0; if (tail == head) expand(); } void addFirst(int x){ if (--head < 0) head = n - 1; if (tail == head) expand(); a[head] = x; } int pollFirst(){ int v = a[head++]; if (head == n) head = 0; return v; } int pollLast(){ if (--tail < 0) tail = n - 1; return a[tail]; } boolean isEmpty(){ return head == tail; } void expand(){ int[] b = new int[n << 1]; int i = 0; while (!isEmpty()) b[i++] = pollFirst(); n <<= 1; a = b; head = 0; tail = i; } } // ================= Tarjan SCC(递归) ================= static final class TarjanSCC { int n, t, sccCnt; int[] dfn, low, st; boolean[] inStack; ArrayList<Integer>[] g; int sp; TarjanSCC(ArrayList<Integer>[] g){ this.g = g; n = g.length; dfn = new int[n]; low = new int[n]; st = new int[n]; inStack = new boolean[n]; t = 1; sp = 0; sccCnt = 0; dfsAll(); } void dfsAll(){ for (int i = 0; i < n; i++) if (dfn[i] == 0) dfs(i); } void dfs(int u){ dfn[u] = low[u] = t++; st[sp++] = u; inStack[u] = true; for (int v : g[u]){ if (dfn[v] == 0){ dfs(v); low[u] = Math.min(low[u], low[v]); } else if (inStack[v]) low[u] = Math.min(low[u], dfn[v]); } if (low[u] == dfn[u]){ while (true){ int v = st[--sp]; inStack[v] = false; if (v == u) break; } sccCnt++; } } } // ================= Hopcroft-Karp 二分图最大匹配 ================= static final class HopcroftKarp { int nL, nR; ArrayList<Integer>[] g; int[] dist, matchR, matchL; HopcroftKarp(int nL, int nR){ this.nL = nL; this.nR = nR; g = new ArrayList[nL]; for (int i=0;i<nL;i++) g[i]=new ArrayList<>(); matchL = new int[nL]; Arrays.fill(matchL, -1); matchR = new int[nR]; Arrays.fill(matchR, -1); dist = new int[nL]; } void addEdge(int u,int v){ g[u].add(v); } boolean bfs(){ Queue<Integer> q = new ArrayDeque<>(); for (int i=0;i<nL;i++){ if (matchL[i]==-1){ dist[i]=0; q.add(i);} else dist[i]=-1;} boolean reach=false; while(!q.isEmpty()){ int u=q.poll(); for(int v:g[u]){ int mu=matchR[v]; if(mu!=-1 && dist[mu]==-1){ dist[mu]=dist[u]+1; q.add(mu);} if(mu==-1) reach=true; } } return reach; } boolean dfs(int u){ for(int v:g[u]){ int mu=matchR[v]; if(mu==-1 || (dist[mu]==dist[u]+1 && dfs(mu))){ matchL[u]=v; matchR[v]=u; return true;} } dist[u]=-1; return false; } int maxMatch(){ int res=0; while(bfs()){ for(int i=0;i<nL;i++) if(matchL[i]==-1 && dfs(i)) res++; } return res; } } // ================= LCA(二进制提升) ================= static final class LCA { int n, LOG; int[][] up; int[] depth; ArrayList<Integer>[] g; @SuppressWarnings("unchecked") LCA(int n){ this.n=n; LOG=32-Integer.numberOfLeadingZeros(n); up=new int[LOG][n]; depth=new int[n]; g=new ArrayList[n]; for(int i=0;i<n;i++) g[i]=new ArrayList<>(); } void addEdge(int u,int v){ g[u].add(v); g[v].add(u); } void build(int root){ Deque<Integer> dq=new ArrayDeque<>(); dq.add(root); up[0][root]=root; depth[root]=0; boolean[] vis=new boolean[n]; vis[root]=true; while(!dq.isEmpty()){ int u=dq.poll(); for(int v:g[u]) if(!vis[v]){ vis[v]=true; up[0][v]=u; depth[v]=depth[u]+1; dq.add(v); } } for(int k=1;k<LOG;k++) for(int i=0;i<n;i++) up[k][i]=up[k-1][up[k-1][i]]; } int lca(int a,int b){ if(depth[a]<depth[b]){int t=a;a=b;b=t;} int diff=depth[a]-depth[b]; for(int k=0;k<LOG;k++) if(((diff>>k)&1)==1) a=up[k][a]; if(a==b) return a; for(int k=LOG-1;k>=0;k--) if(up[k][a]!=up[k][b]){ a=up[k][a]; b=up[k][b]; } return up[0][a]; } } // ================= 字符串算法(KMP / Z / Manacher) ================= static int[] kmpTable(char[] s){ int n=s.length; int[] t=new int[n]; t[0]=0; for(int i=1;i<n;i++){ int j=t[i-1]; while(j>0 && s[i]!=s[j]) j=t[j-1]; if(s[i]==s[j]) j++; t[i]=j; } return t; } static int[] zFunction(char[] s){ int n=s.length; int[] z=new int[n]; int l=0,r=0; for(int i=1;i<n;i++){ if(i<=r) z[i]=Math.min(r-i+1,z[i-l]); while(i+z[i]<n && s[z[i]]==s[i+z[i]]) z[i]++; if(i+z[i]-1>r){ l=i; r=i+z[i]-1; } } return z; } static int[] manacher(String s){ int n=s.length(); int[] d1=new int[n]; int l=0,r=-1; for(int i=0;i<n;i++){ int k=(i>r)?1:Math.min(d1[l+r-i], r-i+1); while(0<=i-k && i+k<n && s.charAt(i-k)==s.charAt(i+k)) k++; d1[i]=k--; if(i+k>r){ l=i-k; r=i+k; } } int[] d2=new int[n]; l=0;r=-1; for(int i=0;i<n;i++){ int k=(i>r)?0:Math.min(d2[l+r-i+1], r-i+1); while(0<=i-k-1 && i+k<n && s.charAt(i-k-1)==s.charAt(i+k)) k++; d2[i]=k--; if(i+k>r){ l=i-k-1; r=i+k; } } int[] res = new int[1]; // placeholder if needed return d1; } // -------- 其他小工具 -------- static long gcd(long a, long b) { while (b != 0) { long t = a % b; a = b; b = t; } return Math.abs(a); } static long powMod(long a, long e, long mod) { long r = 1; a %= mod; while (e > 0) { if ((e & 1) == 1) r = (r * a) % mod; a = (a * a) % mod; e >>= 1; } return r; } }代码解释
最新发布
12-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值