洛谷 P4886 快递员

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MrTinTin/article/details/82930358

题目描述

Bob 的城市里有 nn 个邮递站,由于经济考虑,这些邮递站被 n - 1n−1 条带权无向边相连。即:这 nn 个邮递站构成了一棵树。

Bob 正在应聘一个快递员的工作,他需要送 mm 个商品,第 ii 个商品需要从 uu 送到 vv。由于 Bob 不能带着商品走太长的路,所以对于一次送货,他需要先从快递中心到 uu,再从 uu 回到快递中心,再从快递中心到 vv,最后从 vv 返回快递中心。换句话说,如果设快递中心是 cc 号点,那么他的路径是 c \rightarrow u \rightarrow c \rightarrow v \rightarrow cc→u→c→v→c。

现在 Bob 希望确定一个点作为快递中心,使得他送货所需的最长距离最小。显然,这个最长距离是个偶数,你只需要输出最长距离除以 22 的结果即可。

输入输出格式

输入格式:

第一行输入两个数 n, mn,m,意义如上。

接下来n-1n−1行,每行三个数 u_i, v_i, w_iui​,vi​,wi​,表示一条连接 u_i, v_iui​,vi​,长度为 w_iwi​ 的边。

接下来 mm 行,每行两个整数 u_i, v_iui​,vi​,表示商品的起止位置。

输出格式:

一行一个整数,表示答案。

输入输出样例

输入样例#1: 复制

3 1
1 2 1
2 3 1
1 3

输出样例#1: 复制

2

说明

对于 25\%25% 的数据,满足 1 \leq n, m \leq 10001≤n,m≤1000。

对于 100\%100% 的数据,满足 1 \leq n, m \leq 10^5, 1 \leq w_i \leq 10001≤n,m≤105,1≤wi​≤1000。

先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对。如果这个点在任意一个距离最大的点对之间的路径上,那么答案显然不能再优了,因为这个点对的答案是不能减小了的。如果有两个距离最大的点对不在根的同一子树中,答案也是显然不能再优了的,因为一个点对答案减小的同时,另一个会增大。只有当所有距离最大的点对在根的同一子树中,这时更优答案可能在这个子树里,向这个子树递归处理就行了。为什么说可能?因为往这个子树走的同时可能会存在在另一个子树中原本不是距离最大的点对变为距离最大的点对,所以我们要一直对答案取最小值。直接走最多会走nn次,而如果我们每次都走子树的重心,最多走logNlogN次,所以总时间复杂度O(m\log n)O(mlogn)。

现在讲讲具体怎么实现,主要就难在怎么判断根在不在两个点之间的路径上。求LCALCA是最简单粗暴的方法,但时间复杂度要多一个loglog,其实类似于点分治里的统计,只需要看这个点对的两个点在不在同一子树里就行了,若在,则路径不经过根,反之亦然。

#include<iostream>
#include<cstring>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=100005,INF=100000000;
int head[MAXN],tot;
int n,m;
int x[MAXN],y[MAXN];
int rt,Ans=INF,sz[MAXN],top[MAXN];
int dep[MAXN],vis[MAXN],a[MAXN],ans=INF;
struct Edge{
	int v,w,next;
}e[MAXN<<1];
inline void add(int u,int v,int w)
{
	e[tot].v=v;
	e[tot].w=w;
	e[tot].next=head[u];
	head[u]=tot++;
}
void Getrt(int u,int fa,int all)
{
	int i,max_p=0;
	sz[u]=1;
	for(i=head[u];~i;i=e[i].next){
		int v=e[i].v;
		if(v==fa||vis[v]) continue;
		Getrt(v,u,all);
		sz[u]+=sz[v];
		max_p=max(max_p,sz[v]);
	}
	max_p=max(max_p,all-sz[u]);
	if(max_p<Ans){
		Ans=max_p;
		rt=u;
	}
}
inline void dfs(int u,int fa)
{
	int i;
	for(i=head[u];~i;i=e[i].next){
		int v=e[i].v,w=e[i].w;
		if(v==fa) continue;
		dep[v]=dep[u]+w;
		top[v]=top[u];
		dfs(v,u);
	}
}
inline void solve(int u)
{
	if(vis[u]){
		cout<<ans<<endl;
		return;
	}
	vis[u]=1;
	int i;
	int max_d=0,las=0;
	dep[u]=0;
	a[0]=0;
	for(i=head[u];~i;i=e[i].next){
		int v=e[i].v,w=e[i].w;
		top[v]=v;
		dep[v]=w;
		dfs(v,u);
	}
	f(i,1,m){
		if(dep[x[i]]+dep[y[i]]>max_d){
			max_d=dep[x[i]]+dep[y[i]];
			a[0]=1;
			a[a[0]]=i;
		}
		else if(dep[x[i]]+dep[y[i]]==max_d){
			a[++a[0]]=i;
		}
	}
	ans=min(ans,max_d);
	f(i,1,a[0]){
		if(top[x[a[i]]]!=top[y[a[i]]]){
			cout<<ans<<endl;
			return;
		}
		else{
			if(!las) las=top[x[a[i]]];
			else if(las!=top[x[a[i]]]){
				cout<<ans<<endl;
				return;
			}
		}
	}
	Ans=INF;
	Getrt(las,u,sz[las]);
	solve(rt);
}
int main()
{
//		freopen("data.in","r",stdin);
//	freopen("2.out","w",stdout);
	memset(head,-1,sizeof(head));
	int i,j;
	int u,v,w;
	cin>>n>>m;
	f(i,1,n-1){
		cin>>u>>v>>w;
		add(u,v,w);
		add(v,u,w);
	}
	f(i,1,m){
		cin>>x[i]>>y[i];
	}
	Getrt(1,0,n);
	solve(rt);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/MrTinTin/article/details/82930358