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

 

posted @ 2018-11-09 19:23  Exception2017  阅读(138)  评论(0编辑  收藏  举报