……

解题报告: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[]\)数组。

posted @ 2020-02-19 19:41  童话镇里的星河  阅读(224)  评论(0编辑  收藏  举报