noip2015 运输计划(二分+LCA+树上差分)
公元 2044 年,人类进入了宇宙纪元。L 国有 n个星球,还有 n-1条双向航道,每条航道建立在两个星球之间,这 n-1 条 航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
【输入样例1】 6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5
题解:
题目给的是一颗树,我们可以用LCA求两点的距离,关于删掉那条边正面不好做。显然答案具有单调性,可以二分答案,对于大于mid的路径只有删掉他们的最大公共边才能使答案成立,变成了树上最大覆盖线段。就很好做了。注意要尽可能减小二分范围。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=330000;
const int M=20;
struct E{int x,y,c,next;}mm[N<<1];
int h[N],dep[N],fa[N][M],sum[N],dis[N],L[N],R[N],lca[N],val[N],tt[N];
int n,m,len,l,r,maxl,maxm,maxn,cnt;
inline char gc(){
static char *S,*T,buf[1<<16];
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int rd(){
int x=0;int f=1;char s=gc();
while(s>'9' || s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0' && s<='9') x=(x<<1)+(x<<3)+s-'0',s=gc();
return x*f;
}
inline void ins(int x,int y,int c){
int now=++len;
mm[now].x=x;mm[now].y=y;mm[now].c=c;mm[now].next=h[x];h[x]=len;
}
void dfs(int x,int f){
dep[x]=dep[f]+1;fa[x][0]=f;
for(int k=h[x] ; k ;k=mm[k].next){
int y=mm[k].y;int c=mm[k].c;if(y==f) continue;
sum[y]=sum[x]+c;dis[y]=c;
dfs(y,x);
}
}
void dfs1(int x,int f){
for(int k=h[x];k;k=mm[k].next){
int y=mm[k].y;if(y==f) continue;
dfs1(y,x);
tt[x]+=tt[y];
}
if(tt[x]==cnt) maxn=max(maxn,dis[x]);
}
inline int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int j=M-1;j>=0;j--)
if(dep[fa[x][j]] >= dep[y]) x=fa[x][j];
if(x==y) return x;
for(int j=M-1;j>=0;j--)
if(fa[x][j] != fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
inline bool check(int x){
memset(tt,0,sizeof tt);cnt=0;maxm=0;
for(int i=1;i<=m;i++){
int s=L[i];int t=R[i];int v=val[i];int f=lca[i];
if(v<=x) continue;
cnt++;tt[f]-=2;tt[s]++;tt[t]++;maxm=max(maxm,v);
}
maxn=0;dfs1(1,0);
return maxm-maxn<=x;
}
int main(){
// freopen("transport.in","r",stdin);
n=rd();m=rd();
len=0;memset(h,0,sizeof h);
for(int i=1,x,y,c;i<n;i++){
x=rd();y=rd();c=rd();ins(x,y,c);ins(y,x,c);maxl=max(maxl,c);
}
sum[0]=0;dep[0]=0;dfs(1,0);
for(int j=1;j<M;j++)
for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1,a,b;i<=m;i++){
a=L[i]=rd();b=R[i]=rd();
lca[i]=LCA(a,b);val[i]=sum[a]+sum[b]-2*sum[lca[i]];
r=max(r,val[i]);
}
l=r-maxl;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
printf("%d\n",r+1);
return 0;
}