蓝桥杯 2014 国 C- 套娃 【倍增】

参考:https://www.luogu.com.cn/blog/edisnimorF/solution-p8616

题面

https://www.luogu.com.cn/problem/P8616

分析

套娃u套着v视为u->v建边,那么整张图就是一棵树。查找入度为0的点作为根节点即可。

假设out[i]表示第i个点已经被断开。那么“打开套娃以看大小为x的娃娃”实质就是:从x点出发,一直遇到第一个out[i]=1的点的距离。

对于P操作,假设两点分别为uv。在计算完u->v距离后,需要断开u->v路径上所有的点;同时路径上的每个点也需要断开与其相连的每个点(因为套娃一旦拿开,次级的所有套娃都会被拿出来)。

Q操作则只需要计算距离,不需要断点。

因为查找点的实质是向父节点跳跃,所以只需要倍增即可实现查找(动态)根节点。

O(nlogn)

Code

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>

const int maxn = 1e5 + 10;
int n, m;
int head[maxn], to[maxn << 1], nxt[maxn << 1], val[maxn << 1];
int tot;

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

int N;
int fa[maxn << 1][21 + 1];//节点u的2^k祖先
int depth[maxn << 1];
bool link[maxn << 1];

void dfs1(int u, int x) {//预处理fa[u][k]倍增
    fa[u][0] = x;
    depth[u] = depth[x] + 1;
    for (int i = 1; i <= 21; i++)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (int i = head[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == x) continue;
        //fa[v][0] = u;
        dfs1(v, u);
    }
}

int solve(int x) {//寻找第一个断开的边
    for (int i = N; ~i; i--) {
        if (fa[x][i] && link[fa[x][i]] == 0) x = fa[x][i];
    }
    return x;
}

int rd[maxn << 1], rt;

int main() {
    scanf("%d%d", &n, &m);
    N = log2(n);
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        rd[v]++;
        add(u, v);
        add(v, u);

    }
    for (int i = 1; i <= n; i++)
        if (!rd[i]) {
            rt = i;
            break;
        }
    dfs1(rt, 0);
    link[rt] = 1;
    while (m--) {
        char ch;
        int t;
        std::cin >> ch;
        scanf("%d", &t);
        if (ch == 'P') {
            if (link[t]) {//已经断开
                for (int i = head[t]; i; i = nxt[i])
                    link[to[i]] = 1;
                puts("0");
                continue;
            }
            int top = solve(t);
            int father = fa[top][0];
            printf("%d\n", depth[t] - depth[father]);
            for (;; t = fa[t][0]) {
                link[t] = 1;
                for (int i = head[t]; i; i = nxt[i])
                    link[to[i]] = 1;
                if (t == father) break;
            }
        } else {
            if (link[t]) {
                puts("0");
                continue;
            }
            int top = solve(t);
            int father = fa[top][0];
            printf("%d\n", depth[t] - depth[father]);
        }
    }
    return 0;
}
posted @   SxtoxA  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
12 13
点击右上角即可分享
微信分享提示