阅读程序(第二题):树上倍增求 LCA

by747806 组合题 共 个子题

阅读下面程序,完成后面的判断题和单选题。判断题正确填 A,错误填 B。

树的输入格式为:第一行两个整数 n, q;第二行 n−1 个整数,依次表示结点 2 到结点 n 的父结点编号(保证父结点编号小于该结点编号,结点 1 为根);接下来 q 行,每行两个整数 u, v。以下各题若无特别说明,均以输入

9 8
1 1 2 2 3 3 5 5
4 5
8 9
6 7
8 6
9 3
4 8
5 8
6 2

为例。

#include <algorithm>
#include <cstdio>
#include <cstring>

const int MAXN = 100005;
const int LOG = 17;

int n, q;
int head[MAXN], nxt[MAXN], to[MAXN], tot;
int dep[MAXN], up[MAXN][LOG + 1];

void add(int u, int v) {
    nxt[++tot] = head[u];
    to[tot] = v;
    head[u] = tot;
}

void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    up[u][0] = fa;
    for (int j = 1; j <= LOG; ++j)
        up[u][j] = up[up[u][j - 1]][j - 1];
    for (int e = head[u]; e; e = nxt[e]) {
        int v = to[e];
        if (v != fa) dfs(v, u);
    }
}

int lca(int u, int v) {
    if (dep[u] < dep[v]) std::swap(u, v);
    for (int j = LOG; j >= 0; --j)
        if (dep[u] - (1 << j) >= dep[v])
            u = up[u][j];
    if (u == v) return u;
    for (int j = LOG; j >= 0; --j)
        if (up[u][j] != up[v][j]) {
            u = up[u][j];
            v = up[v][j];
        }
    return up[u][0];
}

int main() {
    scanf("%d%d", &n, &q);
    for (int i = 2; i <= n; ++i) {
        int p;
        scanf("%d", &p);
        add(p, i);
        add(i, p);
    }
    dfs(1, 0);
    long long s = 0;
    for (int i = 1; i <= q; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        int w = lca(u, v);
        printf("%d\n", w);
        s += w;
    }
    printf("%lld\n", s);
    return 0;
}

子题 判断题

判断题:该程序预处理(dfs 求深度并构建倍增表)的时间复杂度为 O(n log n),单次询问 lca 的时间复杂度为 O(n)。( )

A

正确

B

错误

子题 判断题

判断题:以上述输入运行程序,程序共输出 9 行,且最后一行是 20。( )

A

正确

B

错误

子题 判断题

判断题:若把第 31 行的 `for (int j = LOG; j >= 0; --j)` 改为 `for (int j = 0; j <= LOG; ++j)`,其余不变,则以上述输入运行程序时,最后一行的输出会发生变化。( )

A

正确

B

错误

子题 判断题

判断题:程序中 dep[u] 的值等于结点 u 到根结点 1 的路径上所经过的边数。( )

A

正确

B

错误

子题 单选题

以上述输入运行程序,第 2 组询问 lca(8, 9) 的输出为( )。

A

2

B

3

C

5

D

1

子题 单选题

以上述输入运行程序,最后一行输出的整数为( )。

A

14

B

18

C

20

D

24

子题 单选题

程序中 up[u][j] 的含义是( )。

A

编号为 2^j 的结点

B

结点 u 沿父边向上走 2^j 步所到达的祖先结点(若不存在则为 0)

C

结点 u 的子树中深度为 j 的结点

D

结点 u 的第 j 个儿子

正在加载题目数据…
已答 /
子题
该题型需在试卷/作业中作答,单题练习暂不支持
答案解析
讨论
发布
登录后参与讨论 立即登录
发布讨论需先绑定并验证手机号 去绑定手机号
加载中…
我
我
回复 @
回复 @
发送
还没有人讨论,来发表第一条吧