Luogu P2680 运输计划

题目描述

公元20442044 年,人类进入了宇宙纪元。

L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球。

小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_iui​ 号星球沿最快的宇航路径飞行到 v_ivi​ 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_jtj​,并且任意两艘飞船之间不会产生任何干扰。

为了鼓励科技创新, LL 国国王同意小 PP 的物流公司参与 LL 国的航道建设,即允许小PP 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 mm 个运输计划。在虫洞建设完成后,这 mm 个运输计划会同时开始,所有飞船一起出发。当这 mm 个运输计划都完成时,小 PP 的物流公司的阶段性工作就完成了。

如果小 PP 可以*选择将哪一条航道改造成虫洞, 试求出小 PP 的物流公司完成阶段性工作所需要的最短时间是多少?

输入输出格式

输入格式:

 

第一行包括两个正整数 n, mn,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 11 到 nn 编号。

接下来 n-1n−1 行描述航道的建设情况,其中第 ii 行包含三个整数 a_i, b_iai​,bi​ 和 t_iti​,表示第 ii 条双向航道修建在 a_iai​ 与 b_ibi​两个星球之间,任意飞船驶过它所花费的时间为 t_iti​。数据保证 1 \leq a_i,b_i \leq n1≤ai​,bi​≤n 且 0 \leq t_i \leq 10000≤ti​≤1000。

接下来 mm 行描述运输计划的情况,其中第 jj 行包含两个正整数 u_juj​ 和 v_jvj​,表示第 jj 个运输计划是从 u_juj​ 号星球飞往 v_jvj​号星球。数据保证 1 \leq u_i,v_i \leq n1≤ui​,vi​≤n

 

输出格式:

 

一个整数,表示小 PP 的物流公司完成阶段性工作所需要的最短时间。

 

输入输出样例

输入样例#1: 复制

6 3 
1 2 3 
1 6 4 
3 1 7 
4 3 6 
3 5 5 
3 6 
2 5 
4 5

输出样例#1: 复制

11

说明

所有测试数据的范围和特点如下表所示

Luogu P2680 运输计划

请注意常数因子带来的程序效率上的影响。

 

第一步:由于最短,所以想到二分答案

第二步:已知答案,找到所以比答案大的方案,改造成虫洞的边一定在这些方案的交上

第三步:用差分思想求出交,并取出最大的边,把最大的方案减去最大的边,看是否小于等于答案

GG啦

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
inline int read()
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret;
}

int n,m,cnt,l,r,ans,anss,lca;
const int N=6e5+5;
int to[N],nxt[N],w[N],he[N],dep[N],a[N],tree[N];
int f[N][20],fw[N][20],lg[N];

inline void add(int u,int v,int k)
{
	to[++cnt]=v;
	nxt[cnt]=he[u];
	w[cnt]=k;
	he[u]=cnt;
}

void dfs(int fa,int u)
{
	dep[u]=(!fa)?0:dep[fa]+1;
	f[u][0]=fa;
	for(int i=1;i<=lg[dep[u]];i++)
		f[u][i]=f[f[u][i-1]][i-1],
		fw[u][i]=fw[u][i-1]+fw[f[u][i-1]][i-1];
		
	for(int e=he[u];e;e=nxt[e])
	{
		int v=to[e];
		if(v!=fa)
			fw[v][0]=w[e],
			dfs(u,v);
	}
}

void dfs1(int fa,int u,int s)
{
	tree[u]=a[u];
	for(int e=he[u];e;e=nxt[e])
	{
		int v=to[e];
		if(v!=fa)
			dfs1(u,v,w[e]),tree[u]+=tree[v];
	}
	if(tree[u]==cnt) anss=max(anss,s);
}

int LCA(int u,int v)
{
	if(dep[u]>dep[v]) swap(u,v);
	int ret=0;
	while(dep[u]<dep[v])
		ret+=fw[v][lg[dep[v]-dep[u]]],
		v=f[v][lg[dep[v]-dep[u]]];
		
	for(int i=lg[dep[u]];i>=0;i--)
		if(f[u][i]!=f[v][i])
			ret+=fw[v][i]+fw[u][i],
			u=f[u][i],v=f[v][i];
	if(u!=v)
		ret+=fw[u][0]+fw[v][0],u=f[u][0];
	lca=u;
	return ret;
}
struct NA{
	int l,r,t,lca;
}e[N];

bool cmp(NA i,NA j)
{
	return i.t>j.t;
}

int main()
{
	n=read(),m=read();
	cnt=0;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),k=read();
		add(u,v,k),add(v,u,k);
	}
	lg[0]=-1;
	for(int i=1;i<=n;i++) 
		lg[i]=lg[i>>1]+1;
	cnt=0;
	dfs(0,1);
	for(int i=1;i<=m;i++)
		lca=0,
		e[i].l=read(),e[i].r=read(),
		e[i].t=LCA(e[i].l,e[i].r),r=max(r,e[i].t),e[i].lca=lca;
	sort(e+1,e+m+1,cmp);
	
	l=0; ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		cnt=0;anss=0; 
		for(int i=0;i<=n;i++) a[i]=0;
		while(e[++cnt].t>mid)
			a[e[cnt].l]++,a[e[cnt].r]++,
			a[e[cnt].lca]-=2;
		if(e[cnt].t<=mid) cnt--;
		dfs1(0,1,0);
		if(e[1].t-anss>mid) l=mid+1;
				else ans=mid,r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
}