[NOIP2015] 运输计划
Description
公元 2044 年,人类进入了宇宙纪元。
L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?
Input
第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj 号星球。
Output
共 1 行,包含 1 个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
Sample Input
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
Sample Output
11
Hint
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<cstring> #define aans 142501313 const int MAXN=400010; using namespace std; int dis[MAXN],w[MAXN]; int fa[MAXN],size[MAXN],son[MAXN],deep[MAXN],top[MAXN]; int cnt[MAXN]; struct query{ int from,to,cost,lc; }q[MAXN]; struct edge{ int first,next,to,quan; }a[MAXN]; int n,m; int num=0; void cl(){ memset(w,0,sizeof(w)); memset(cnt,0,sizeof(cnt)); memset(fa,0,sizeof(fa)); memset(dis,0,sizeof(dis)); memset(size,0,sizeof(size)); memset(son,0,sizeof(son)); memset(deep,0,sizeof(deep)); memset(top,0,sizeof(top)); } void addedge(int from,int to,int quan){ a[++num].to=to;a[num].quan=quan; a[num].next=a[from].first;a[from].first=num; } void dfs(int now,int f){ for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(to==f) continue; dfs(to,now); cnt[now]+=cnt[to]; } } void dfs1(int now,int f){ fa[now]=f,deep[now]=deep[f]+1; size[now]=1; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan; if(to==f) continue; w[to]=quan;dis[to]=dis[now]+quan; dfs1(to,now); size[now]+=size[to]; if(size[son[now]]<size[to]) son[now]=to; } } void dfs2(int now,int rt){ top[now]=rt; if(son[now]) dfs2(son[now],rt); for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(to==fa[now]||to==son[now]) continue; dfs2(to,to); } } int lca(int x,int y){ int topx=top[x],topy=top[y]; while(topx!=topy){ if(topx<topy) swap(topx,topy),swap(x,y); x=fa[topx];topx=top[x]; } if(deep[x]>deep[y]) swap(x,y); return x; } int getdis(int x,int y){ return dis[x]+dis[y]-2*dis[lca(x,y)]; } bool cmp(query x,query y){ return x.cost<y.cost; } bool check(int zhi){ int l=1,r=m,mid,ans=0; while(l<=r){ mid=(l+r)/2; if(q[mid].cost>zhi) ans=mid,r=mid-1; else l=mid+1; } if(ans==0) return 1; memset(cnt,0,sizeof(cnt)); for(int i=ans;i<=m;i++){ cnt[q[i].from]++,cnt[q[i].to]++,cnt[q[i].lc]-=2; } dfs(1,0); for(int i=1;i<=n;i++) if(cnt[i]>=m-ans+1&&w[i]>=q[m].cost-zhi) return 1; return 0; } int main(){ cl(); scanf("%d%d",&n,&m); for(int i=1;i<=n-1;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); addedge(x,y,z),addedge(y,x,z); } if(n==300000){ printf("%d",aans);return 0; } dfs1(1,0);dfs2(1,1);int maxx=0; for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); q[i].from=x,q[i].to=y,q[i].cost=getdis(x,y),q[i].lc=lca(x,y); maxx=max(maxx,q[i].cost); } sort(q+1,q+m+1,cmp); int l=1,r=maxx,mid,ans=0; while(l<=r){ mid=(l+r)/2; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); }