AcWing 3555. 二叉树

第一种做法是dfs。但是注意,如果是非常单纯的dfs,要把每个节点可以到达的所有节点都记录下来(父节点+两个子节点)。如果只记录了子节点,没记录父节点,就失去了一个方向,肯定出错。

例如求2和6之间的路径:因为这是一棵树,所以从a到b的路径只有唯一的一条。

void dfs(int cur, int b, int depth){
	if(cur == b){
		ans = depth;
		return ;
	}
	for(int i = 0; i < 3; i++){
		int x = v[cur][i];
		if(x != -1 && !vis[x]) {
			vis[x] = 1;
			dfs(x, b, depth + 1); 
		}
	}
	return ;
}
int main(){
	scanf("%d", &t);
	while(t--){
		int n, m;
		scanf("%d%d", &n, &m);
		memset(v, -1, sizeof(v));
		for(int i = 1; i <= n; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			v[i][0] = a; 
			v[i][1] = b; 
			if(a != -1) v[a][2] = i;
			if(b != -1) v[b][2] = i;
		}
		ans = 0;
		memset(vis, false, sizeof(vis));
		for(int i = 1; i <= m; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			vis[a] = 1;
			dfs(a, b, 0);
			printf("%d\n", ans);
		}
	} 
	return 0;

 但是dfs明显有点麻烦,那么我们使用LCA。

2.LCA:最近公共祖先。在二叉树中找到两个节点的最近的公共根节点。

这题求a和b之间的距离,那么我们在建树的时候就已经算出了每个节点到根节点之间的距离。然后我们来看看根据这个距离数组怎么计算两个节点之间的路径。

 这么画个图是不是就知道怎么通过各个节点到根节点的距离计算任意两点之间的路径了!

那么我们怎么计算各个点到根节点的距离呢?很简单,从它的父节点传递过来一个depth,那么当前节点到根节点的距离一定是父节点的深度+1.

那么我们怎么计算两个点的最近公共祖先呢?很简单,一直去找父亲,直到他们的父亲是同一个人。

好了。现在上代码(这个代码除了输出,看样子就是最简单的lca模板了,积累一下):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int N = 1010;
const int M = 1010;
int l[N];
int r[N];
int dep[N];
int p[N];
int n, m, t; 
void dfs(int root){  //找根节点到各个节点的距离
    if(root == -1) return ;
    if(l[root] > 0) dep[l[root]] = dep[root] + 1;
    if(r[root] > 0) dep[r[root]] = dep[root] + 1;
    
    dfs(l[root]);
    dfs(r[root]);
}
int main(){
	scanf("%d", &t);
	while(t--){
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			l[i] = a;
			r[i] = b;
			if(a != -1) p[a] = i;
			if(b != -1) p[b] = i;
		}
		dfs(1);
		for(int i = 1; i <= m; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			int x = a;
			int y = b;
			while(a != b){
			    if(dep[a] > dep[b]){
			        a = p[a];
			    }else{
			        b = p[b];
			    }
			}   
			
			printf("%d\n", dep[x] + dep[y] - 2 * dep[a]);
		}
	} 
	
	return 0;
} 

还有用链表的形式查找两个节点的最近公共祖先,代码如下:

TreeNode* lowestCommonAncestor(TreeNode* root,TreeNode* p,TreeNode* q){
    //已经到叶子节点了,找到p或者找到q了,因为值是唯一的,所以在另一半的子树上要么没有,要么剩下其他的
    if(root==NULL||root==p||root==q) return root;   
    TreeNode* left=lowestCommonAncestor(root->left,p,q);  //递归到左子树
    TreeNode* right=lowestCommonAncestor(root->right,p,q);  //递归到右子树
    if(left==NULL&&right==NULL) return NULL;  //都不在树中
    else if(left!=NULL&&right!=NULL) return root;  //左右子树各有一个,那么说明公共祖先是根节点
    else return left==NULL?right:left;
}

就到这吧,我的脑子真的很不好使,但是我应该给我自己一点积极的暗示!

我有一个好脑子!

我有一个好脑子!

我有一个好脑子!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值