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