ZOJ 3820 Building Fire Stations

题意:在一棵树上找两个点,使其他每个点到这两个点的较大值中的最大值最小

思路:树的直径先来一发,然后找中点分树然后两棵树各找直径,两个点就是两个直径的中点(并不知道直接四等分点会怎么样,但显然不对,吧)

感觉细节还蛮多,不过代码很短。。(据说两个点不能是同一个点,反正我的似乎会自动屏蔽)

代码:

#include <bits/stdc++.h>
#define N 200009
#define gc getchar()
using namespace std;
int n,first[N],number,x,y;
int q[N],bs[N],pre[N],Far,head,tail,rt1,rt2,deep[N];
int a1,b1,a3,b3,ans;
struct edge
{
	int to,next;
	void add(int x,int y)
	{
		to=y,next=first[x],first[x]=number;
	}
}e[N<<1];
int read()
{
	int x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	int s=ch-48;
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
	return x*s;
}
int bfs(int x,int y)
{
	int far=0;
	q[head=tail=1]=x;
	memset(bs,0,sizeof(bs));
	bs[x]=1;
	while (head<=tail)
	{
		int now=q[head++];
		if (bs[now]>bs[far]) far=now;
		for (int i=first[now];i;i=e[i].next)
			if (!bs[e[i].to]&&e[i].to!=y)
			{
				pre[e[i].to]=now;
				bs[e[i].to]=bs[now]+1;
				q[++tail]=e[i].to;
			}
	}
	return far;
}
int get(int x,int len)
{
	for (int i=1;i<=len;i++) x=pre[x];
	return x;
}
int main()
{
	int T=read();
	while (T--)
	{
		n=read();
		memset(first,0,sizeof(first));
		number=0;
		for (int i=1;i<n;i++)
		{
			x=read(),y=read();
			e[++number].add(x,y),e[++number].add(y,x);
		}
		Far=bfs(bfs(1,0),0);
		rt1=get(Far,(bs[Far]-1)/2);
		rt2=pre[rt1];
		a1=bfs(bfs(rt1,rt2),rt2);
		a3=get(a1,(bs[a1]-1)/2);
		ans=bs[a1]/2;
		b1=bfs(bfs(rt2,rt1),rt1);
		b3=get(b1,(bs[b1]-1)/2);
		ans=max(ans,bs[b1]/2);
		printf("%d %d %d\n",ans,a3,b3);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值