Comet OJ CCPC-Wannafly Winter Camp Day8 A Aqours

A Aqours

链接

分析:

  给出的点可以视为是按照BFS序给的,也就是说从浅到深给出。可以再给每个节点u维护一个f值,表示离u最近的叶子节点到它的距离。

  所以每当扫到一个叶子节点,就可以暴力往根节点跳,边跳边更新f值,直到跳到一个已被其他叶子节 点跳到过的节点为止。 那么对于当前的叶子节点,离它最近的编号小于它的叶子节点到它的距离就是跳到这个终止节点的f值 +跳的步数。

  在求完之后,还要从上述的终止节点沿着原路更新一下f值,因为可能当前叶子比较深但之前有比较浅 的叶子节点。

  因为点是按从浅到深的顺序给出,所以一个节点的f值只会被最先跳到它的叶子节点赋值一次,也只会 被更新一次,所以复杂度是 O(n) 的。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define pa pair<int,int>
#define Fi first
#define Se second
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 6000005;

int g[N], isleaf[N], d[N], fa[N], ans[N];

int main() {
    int n = read();
    if (n == 1) { printf("1 -1"); return 0; }
    for (int i = 2; i <= n; ++i) isleaf[i] = 1;
    for (int i = 2; i <= n; ++i) {
        fa[i] = read();
        isleaf[fa[i]] = 0;
        d[i] = d[fa[i]] + 1;
    }
    for (int i = 1; i <= n; ++i) g[i] = 1e9;
    bool fir = 0;
    for (int i = 2; i <= n; ++i) {
        if (!isleaf[i]) continue ;
        int x = i, y;
        g[x] = 0;
        while (fa[x]) {
            if (g[fa[x]] == 1e9) {
                g[fa[x]] = g[x] + 1;
                x = fa[x];
                ans[i] ++;
            }
            else {
                ans[i] += g[fa[x]] + 1; 
                break;
            }
        }
        if (!fir) { printf("%d -1
", i), fir = 1; continue; }
        else printf("%d %d
", i, ans[i]);
        
        y = fa[x], x = i;
        while (x != y) {
            g[x] = min(g[x], g[y] + d[x] - d[y]);
            x = fa[x];
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10356519.html