1. 程式人生 > >Luogu P2680 運輸計劃

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

說明

所有測試資料的範圍和特點如下表所示

請注意常數因子帶來的程式效率上的影響。

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

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

第三步:用差分思想求出交,並取出最大的邊,把最大的方案減去最大的邊,看是否小於等於答案

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;
}