解题报告:luogu P5536 【XR-3】核心城市

时间:2022-06-12 20:21:25

题目链接:P5536 【XR-3】核心城市
这题是某次月赛题。
这题我完全是看标签猜的。
优先选择直径中点即可,这里重要的是互通,很容易想到用堆维护可选的,预处理直径和距叶节点距离即可(最近),实质上是将无根树转化为以中点为根的有根树。
发现第二次(dfs)处理的(deg[])只有直径一侧不是我们所要的距叶节点距离,这样就压掉了一次(dfs),我还压掉了一个(vis[])数组(嘚瑟),原理很简单,不说了吧。
复杂度是(O(nlogn))(瓶颈在排序),可以通过本题。

(Code):

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=100005;
priority_queue<pair<int ,int> >q;
struct node
{
    int to,nxt;
}e[MAXN<<1];
int dep[MAXN],maxn=0,rt[MAXN],c=0;
int head[MAXN],cnt=0;
void add(int u,int v)
{
    e[  cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
int n,k,l,r;
void dfs1(int cur,int fa,int step)
{
    dep[cur]=step;
    if(dep[cur]>dep[maxn]) maxn=cur;
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int j=e[i].to;
        if(j==fa) continue;
        dfs1(j,cur,step 1); 
    }
}
int dfs2(int cur,int fa)
{
    dep[cur]=1;
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int j=e[i].to;
        if(j==fa) continue;
        dep[cur]=max(dep[cur],dfs2(j,cur) 1);
    }
    rt[dep[cur]]=cur;
    c=max(c,dep[cur]);
    return dep[cur];
}
int mid,d/,*vis[MAXN]*/;
void work()
{
    int now=rt[mid];
    //vis[now]=1;
    q.push(make_pair(dep[now],now));
    while(k--)
    {
        now=q.top().second;
        q.pop();
        for(int i=head[now];i;i=e[i].nxt)
        {
            int j=e[i].to;
            if(dep[j]<dep[now])
            {
                q.push(make_pair(dep[j],j));
                //vis[j]=1;
            }
        }
    }
    printf("%dn",q.top().first);
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i  )
    {
        scanf("%d%d",&l,&r);
        add(l,r);
        add(r,l);
    }
    dfs1(1,0,1);
    memset(dep,0,sizeof(dep));
    d=dfs2(maxn,0);
    mid=(d/2) 1;
    for(int i=mid 1;i<=c;i  ) dep[rt[i]]=2*dep[rt[mid]]-dep[rt[i]];
    work();
    return 0;
}

(放心,我把调试语句删掉了,注释掉的是(vis[])数组。