noip2015运输计划解题报告

【题目描述】


公元 2044 年,人类进入了宇宙纪元。

L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。

小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性♂工作所需要的最短时间是多少?


【输入格式】


第一行包括两个正整数 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 的物流公司完成阶段性工作所需要的最短时间。

【样例输入】

6 3 
1 2 3 
1 6 4 
3 1 7 
4 3 6 
3 5 5 
3 6 
2 5 
4 5

【样例输出】

11

【提示】


所有测试数据的范围和特点如下表所示

请注意常数因子带来的程序效率上的影响。

题解:

考虑二分最终答案

判断答案是否合法可以将所有运输计划时间大于当前时间的路径上打tag

只需要判断存不存在一条边使得tag==运输计划时间大于当前时间的总个数并且最长路径-这条边长<=当前时间

可以用树上差分(在叶子节点打上tag在lca处回收tag)解决 求lca用tarjan 时间复杂度O(nα(n))

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=300000+10;
struct Edge{
	int t,v,next;
}E[maxn*2];
int head[maxn];
int fr[maxn],to[maxn];
int n,m;
int de[maxn];
int cnt[maxn];
int lc[maxn];
int dr[maxn];
int v[maxn];
int clt;
int maxd;
int edge=1;
struct Lca{
	int t,v,next;
}L[maxn*2];
int Lc=1;
int Lhead[maxn];
int fa[maxn];
int vis[maxn];
inline int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void read(int &x){
	x=0;
	char c=getchar();
	while(c<'0'||c>'9')
		c=getchar();
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
}
inline void insert(int f,int t,int V){
	E[edge].t=t,E[edge].v=V,E[edge].next=head[f],head[f]=edge++;
	E[edge].t=f,E[edge].v=V,E[edge].next=head[t],head[t]=edge++;
}
inline void Insert(int f,int t,int V){
	L[Lc].t=t,L[Lc].v=V,L[Lc].next=Lhead[f],Lhead[f]=Lc++;
	L[Lc].t=f,L[Lc].v=V,L[Lc].next=Lhead[t],Lhead[t]=Lc++;
}
inline void dfs1(int x,int f,int di){
	de[x]=di;
	for(int i=head[x];i;i=E[i].next){
		int u=E[i].t;
		if(u==f)
			continue;
		dfs1(u,x,di+E[i].v);
		v[u]=E[i].v;
	}
}
inline void dfs2(int x){
	vis[x]=1;
	for(int i=head[x];i;i=E[i].next){
		int u=E[i].t;
		if(!vis[u]){
			dfs2(u);
			fa[u]=x;
		}
	}
	for(int i=Lhead[x];i;i=L[i].next){
		int u=L[i].t;
		if(vis[u]){
			int lca=find(u);
			dr[L[i].v]=de[x]+de[u]-2*de[lca];
		}
	}
}
inline void dfs(int x,int f){
	for(int i=head[x];i;i=E[i].next){
		int u=E[i].t;
		if(u==f)
			continue;
		dfs(u,x);
		cnt[x]+=cnt[u];
	}
	if(cnt[x]==clt&&maxd<v[x])
		maxd=v[x];
}
inline bool check(int x){
	memset(cnt,0,sizeof(cnt));
	clt=0;
	int maxx=0;
	for(int i=1;i<=m;i++){
		if(dr[i]>x){
			clt++;
			cnt[fr[i]]++,cnt[to[i]]++;
			cnt[lc[i]]-=2;
			maxx=max(dr[i],maxx);
		}
	}
	maxd=0;
	dfs(1,0);
	if(maxd+x>=maxx)
		return true;
	return false;
}
int main(){
	freopen("transport.in","r",stdin);
	freopen("transport.out","w",stdout);
	int x,y,z;
	read(n),read(m);
	int summ=0;
	int minn=0x7fffffff;
	for(int i=1;i<n;i++){
		//scanf("%d %d %d",&x,&y,&z);
		read(x),read(y),read(z);
		insert(x,y,z);
		summ+=z;
		minn=min(minn,z);
	}
	for(int i=1;i<=n;i++)
		fa[i]=i;
	dfs1(1,0,0);
	for(int i=1;i<=m;i++){
		read(fr[i]),read(to[i]);
		Insert(fr[i],to[i],i);
	}
	dfs2(1);
	int l=minn,r=summ;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(check(mid))
			r=mid;
		else l=mid+1;
	}
	if(check(l))
		printf("%d\n",l);
	else printf("%d\n",r);
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值