二叉树的问题-洛谷P3884

羊爸
羊爸
Published on 2025-04-23 / 21 Visits
0
0

P3884 [JLOI2009] 二叉树问题

by小儿投稿

来我们看一下问题

给定一颗以 1 号结点为根的二叉树,请求出其深度、宽度和两个指定节点 x ,y 之间的距离。

深度简单,就是树有多少层呗。

宽度也简单,找到节点数最多的层数的节点树呗。

那这个指定节点x,y之间的距离是什么玩意呢?

请看VCR这句话

宽度表示二叉树上同一层最多的结点个数,节点 u,v 之间的距离表示从 uv 的最短有向路径上向根节点的边数的两倍加上向叶节点的边数。

怎么理解这句话呢,不如说我们用样例给的86做为例子吧

enter image description here

看图,这里8到最小公共祖先的距离为36到最小公共祖先的距离为2,那么他们的距离为:

(3*2)+2 = 8

综合起来就是(x*2)+y,那要求得问题解决了,那么最小公共祖先怎么求呢

我们可以将yx也行)到根节点(注意这里是整棵树的根节点也就是1)中经过的的点全部标记,在让x向根节点走,第一个遇到的被标记的点就是最小公共祖先

最小公共祖先求到了,剩下的会做了吧(别告诉我层数都不会算)

code:

#include<bits/stdc++.h>
using namespace std;
struct node{
    int l,r;
}a[110];
int b[110],vis[110];
int f[110],d[110],ans1,ans2,ans3;
void init(int now,int sum){
    f[now] = sum;
    d[sum]++;
    ans1 = max(ans1,sum);
    ans2 = max(ans2,d[sum]);
    if(a[now].l != -1){
        init(a[now].l,sum+1);
    }
    if(a[now].r != -1){
        init(a[now].r,sum+1);
    }
}

void lca(int now){
    if(now == -1){
        return;
    }
    vis[now] = 1;
    lca(b[now]);
}
int main(){
    memset(a,-1,sizeof(a));
    memset(b,-1,sizeof(b));
    memset(d,0,sizeof(d));
    memset(f,0,sizeof(f));
    memset(vis,0,sizeof(vis));
    int n,p,q;
    cin>> n;
    for(int i = 1;i < n;i++){
        int L,R;
        cin>> L >> R;
        if(a[L].l == -1){
            a[L].l = R;
        }else{
            a[L].r = R;
        }
        b[R] = L;
    }
    cin>> p >> q;
    init(1,1);
    lca(q);
    int t = 0;
    for(int i = p;i != -1;i = b[i]){
        if(vis[i]){
            t = i;
            break;
        }
    }
    ans3 = (f[p]-f[t])*2+(f[q]-f[t]);
    cout<< ans1 << "\n" << ans2 << "\n" << ans3;
    return 0;
}

Comment