运输计划
题目背景
公元 2044 年,人类进入了宇宙纪元。
题目描述
L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物
流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?
输入输出格式
输入格式:
输入文件名为 transport.in。
第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第
i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j个 运输计划是从 uj 号星球飞往 vj 号星球。
输出格式:
输出 共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
说明
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
思路:
先二分,然后check(),从最长的路径中减去重边中最长的,判断得到的距离是否小于mid、
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> #include<cmath> using namespace std; const int N=300001; int n,m; int depth[N]; int h[N],nex[N*2],to[N*2],w[N*2],cnt; int lca[N],sum[N],f[N][31]; int s[N],e[N]; int chenge[N]; int l,r; void build(int x) { r=max(r,sum[x]); for(int i=h[x];i;i=nex[i]) { int t=to[i]; if(t==f[x][0]) continue; depth[t]=depth[x]+1; sum[t]=sum[x]+w[i]; f[t][0]=x; build(t); } } int LCA(int x,int y) { if(depth[x]<depth[y]) swap(x,y); for(int i=30;i>=0;i--) if(f[x][0]&&depth[f[x][i]]>=depth[y]) x=f[x][i]; if(x==y) return x; for(int i=30;i>=0;i--) if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } x=f[x][0]; return x; } void dfs(int x) { for(int i=h[x];i;i=nex[i]) { if(to[i]==f[x][0]) continue; dfs(to[i]); chenge[x]=chenge[x]+chenge[to[i]]; } return ; } bool check(int mid) { memset(chenge,0,sizeof chenge); int sss=0,maxn=0,maxdis=0; for(int i=1;i<=m;i++) if(sum[s[i]]+sum[e[i]]-2*sum[lca[i]]>mid) { sss++; if(sum[s[i]]+sum[e[i]]-2*sum[lca[i]]>maxdis) maxdis=sum[s[i]]+sum[e[i]]-2*sum[lca[i]]; chenge[s[i]]++; chenge[e[i]]++; chenge[lca[i]]-=2; } dfs(1); for(int i=2;i<=n;i++) if(chenge[i]>=sss&&sum[i]-sum[f[i][0]]>maxn) maxn=sum[i]-sum[f[i][0]]; if(maxdis-maxn>mid) return 0; return 1; } int main() { scanf("%d%d",&n,&m); for(int i=1,u,v,z;i<n;i++) { scanf("%d%d%d",&u,&v,&z); to[++cnt]=v;nex[cnt]=h[u];h[u]=cnt;w[cnt]=z; to[++cnt]=u,nex[cnt]=h[v];h[v]=cnt;w[cnt]=z; } depth[1]=1;f[1][0]=1; build(1); for(int i=1;i<=30;i++) for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; for(int i=1;i<=m;i++) { scanf("%d%d",&s[i],&e[i]); lca[i]=LCA(s[i],e[i]); } l=0;r=r*2; while (l<r) { int mid=(l+r)/2; if (check(mid)) r=mid; else l=mid+1; } cout<<l; return 0; }