解题报告:luogu P5536 【XR-3】核心城市
题目链接: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("%d\n",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[]\)数组。