蓝桥杯-第九届决赛——版本分支 已过 含题目链接

蓝桥杯-第九届决赛——版本分支

题目链接 http://oj.ecustacm.cn/problem.php?id=1400

在这里插入图片描述

查询是自下而上的,所以本质上是如何往上跳的最快。本质上内存够大,树上的每个位置把祖先节点都存一遍就能o1查询了,但是内存不够,所以需要加速这个跳跃查询。
根据自底向上的特性 所以只需要记录2的幂次方的跳跃。

比如 1 2 3 4 5 6 7 8 9 10
n 存{ 1 , 2 , 4 , 8 … }。可以向上跳的距离记录。
10 存 { 1 ,2 , 4 , 8 }
9 存 { 1 , 2 , 4 , 8 }
8 存 { 1 , 2 , 4 , 8}
7 存 { 1 , 2 , 4 }

这样 每个数字最多村log(n)个数字 就能塞下了 ,然后最多向上跳log(n)次就可以向上跳到任何位置

然后 就是向上跳跃,
例如:
比如10 需要寻找7,需要向上跳三次 ,就从10号位置先向上跳两次,再从8号位置向上跳一次,总共跳三次
例如:10 跳到3 ,先向上跳4次到6,然后6向上跳两次到4 , 4 向上跳一次到3 。

#pragma GCC optimize(2)

#include <bits/stdc++.h>
using namespace std;

inline int read() {
    char ch = getchar();
    int x = 0, f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

typedef vector<int> VI;
typedef vector<VI> VVI;

struct node {
    pair<int, int> fa_vec[20]; // 半程二分
    int pair_size = 0;
    int depth_num; // 记录当前深度
} my_node[100005];

/*
    预处理
 */
void dfs(vector<VI> &my_tree, int dad, int node, int depth, VI &depth_tag) {
    depth_tag[depth] = node;
    my_node[node].depth_num = depth;
    int tem_depth = depth;
    int count = 0;
    while (tem_depth) {
        my_node[node].fa_vec[count] =
            make_pair(depth - tem_depth, depth_tag[depth - tem_depth]);
        tem_depth /= 2;
        count += 1;
    }
    my_node[node].pair_size = count;

    for (int i = 0; i < my_tree[node].size(); i++) {
        dfs(my_tree, node, my_tree[node][i], depth + 1, depth_tag);
    }
}

int get_ancestor_node(int node, int ancestor_depth) {

    int tem_node = node;
    int i = 0;
    while (my_node[tem_node].depth_num > ancestor_depth) {
        for (; i < my_node[tem_node].pair_size; ++i) {
            if (my_node[tem_node].fa_vec[i].first >= ancestor_depth) {
                tem_node = my_node[tem_node].fa_vec[i].second;
                break;
            }
        }
    }
    return tem_node;
}

bool query(int x, int y) {
    if (my_node[x].depth_num > my_node[y].depth_num) {
        return false;
    }
    int result_node = get_ancestor_node(y, my_node[x].depth_num);
    if (result_node == x) {
        return true;
    }
    return false;
}

void run() {

    int n, q;
    // scanf("%d %d ", &n, &q);
    n = read();
    q = read();
    VVI my_tree;
    VI depth_tag;
    for (int i = 0; i <= n; i++) {
        my_tree.push_back(VI());
        depth_tag.push_back(-1);
    }
    int x, y;
    for (int i = 0; i < n - 1; i++) {
        // scanf("%d %d ", &x, &y);
        x = read();
        y = read();
        my_tree[x].push_back(y);
    }

    dfs(my_tree, 0, 1, 1, depth_tag);

    for (int i = 0; i < q; i++) {
        // scanf("%d %d ", &x, &y);
        x = read();
        y = read();
        if (query(x, y)) {
            printf("YES\n");
        } else {
            printf("NO\n");
        }
    }
}

int main() {
#if defined(__APPLE__)
    freopen("./slyar.in", "r+", stdin);
    freopen("./slyar.out", "w+", stdout);
#endif
    run();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值