luoguP5536 【XR-3】核心城市

树的直径

(dfs1)求直径的一端点

(dfs2)求整个直径的长度,并保存下直径上的所有点

然后(for)一边 (f) 数组(保存下来的点),求出中点

(dfs3)(mid)为根来统计所有节点的深度,并算出每个节点能到达的最大深度

然后求出相对深度,排序之后,前$ k$ 个 即满足题目要求,输出(k + 1) 就是答案

因为在做差求相对深度的时候没有(+1) ,所以答案最后要$+1 $

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int e[N*2],ne[N*2],h[N],idx,f[N],d[N],mx,pos,mxd[N],dd[N];
void add(int a,int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}
bool cmp(int a,int b) {
    return a > b;
}
void dfs1(int u,int fa) {// 求直径
    if(mx < d[u]) mx = d[u],pos = u;
    for(int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        d[j] = d[u] + 1;
        dfs1(j,u);
    }
}
void dfs2(int u,int fa) {
    if(mx < d[u]) mx = d[u],pos = u;
    for(int i = h[u]; ~i;i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        d[j] = d[u] + 1;
        f[j] = u;// 记录直径上的点
        dfs2(j,u);
    }
}
void dfs3(int u,int fa) {
    mxd[u] = d[u];
    for(int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        d[j] = d[u] + 1;
        dfs3(j,u);
        mxd[u] = max(mxd[u],mxd[j]);
    }
}

int main() {
    int n,k;
    memset(h,-1,sizeof h);
    cin >> n >> k;
    for(int i = 0;i < n - 1; ++i) {
        int a,b;
        cin >> a >> b;
        add(a,b);
        add(b,a);
    }
    dfs1(1,0);
    memset(d,0,sizeof d);
    mx = 0;
    dfs2(pos,0);// 找直径
    int mid = pos;
    for(int i = 1;i <= (d[pos] + 1) / 2; ++i) mid = f[mid];
    memset(d,0,sizeof d);
    dfs3(mid,0);// 以中点为根,遍历树的深度,mxd[i] 代表i当前能走多深
    for(int i = 1;i <= n; ++i) dd[i] = mxd[i] - d[i];// 当前i能走多深 减去 当前的深度,就得到了绝对深度
    sort(dd + 1,dd + 1 + n,cmp);// 前 k 个城市联通 即可,第 k + 1即是答案
    cout << dd[k + 1] + 1;// mxd - d 是距离,但是没有加1,比如 1 到 5 的距离是  5 - 1 + 1,不是 5 - 1
    return 0;
}
原文地址:https://www.cnblogs.com/lukelmouse/p/13163411.html