列表

详情


NC16465. [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的物流公司完成阶段性工作所需要的最短时间。

示例1

输入:

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

输出:

11

说明:

将第1条航道改造成虫洞:则三个计划耗时分别为:11、12、11,故需要花费的时间为12。
将第2条航道改造成虫洞:则三个计划耗时分别为:7、15、11,故需要花费的时间为15。
将第3条航道改造成虫洞:则三个计划耗时分别为:4、8、11,故需要花费的时间为11。
将第4条航道改造成虫洞:则三个计划耗时分别为:11、15、5,故需要花费的时间为15。
将第5条航道改造成虫洞:则三个计划耗时分别为:11、10、6,故需要花费的时间为11。
故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1593ms, 内存消耗: 48604K, 提交时间: 2020-03-09 16:56:50

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define maxn 300005
using namespace std;
struct yyy{int t,nex,cost;}e[2*maxn];
int depth[maxn]={0},fa[maxn][22]={0},lg[maxn]={0},head[maxn];//数组depth表示每个节点的深度,fa[i][j]表示节点i的2j级祖先 
int tot;
int dis[maxn];
void add(int x,int y,int z)
{
    e[++tot].t=y; 
    e[tot].nex=head[x];
    e[tot].cost=z;
    head[x]=tot;
}
vector<int>seq;
void dfs(int p,int fath,int cost)
{
	seq.push_back(p);
	dis[p]=dis[fath]+cost;
    depth[p]=depth[fath]+1;
    fa[p][0]=fath;
    for(int i=1;(1<<i)<=depth[p];i++)
      fa[p][i]=fa[fa[p][i-1]][i-1];
    for(int i=head[p];i;i=e[i].nex)
      if(e[i].t!=fath)
        dfs(e[i].t,p,e[i].cost);
}
int lca(int x,int y)
{
    if(depth[x]<depth[y])
      swap(x,y);
    for(int i=0;i<22;i++)if((depth[x]-depth[y])&(1<<i))x=fa[x][i];
	if(x==y)
      return x;
    for(int k=lg[depth[x]]-1;k>=0;k--)
      if(fa[x][k]!=fa[y][k])
        x=fa[x][k], y=fa[y][k];
    return fa[x][0];
}
int n,m;
int u[maxn],v[maxn],LCA[maxn];
int sum[maxn];
bool check(int x)
{
	memset(sum,0,sizeof(sum));
	int maxd=0,cnt=0;
	for (int i=0;i<m;i++)
	{
		int d=dis[u[i]]+dis[v[i]]-2*dis[LCA[i]];
		if (d>x)
		{
			sum[u[i]]++,sum[v[i]]++,sum[LCA[i]]-=2;
			cnt++;
			maxd=max(maxd,d-x);
		}
	}
	if (!cnt) return 1;
	for (int i=seq.size()-1;i>0;i--)
	{
		int p=seq[i];
		sum[fa[p][0]]+=sum[p];
	}
	for (int i=2;i<=n;i++)
	{
		if (sum[i]==cnt&&dis[i]-dis[fa[i][0]]>=maxd)
		return 1;
	}
	return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++)
    {
        int x,y,z;  scanf("%d%d%d",&x,&y,&z);
        add(x,y,z); add(y,x,z);
    }
    dfs(1,0,0);
    for(int i=1;i<=n;i++)
      lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    for (int i=0;i<m;i++)
    {
    	scanf("%d%d",&u[i],&v[i]);
    	LCA[i]=lca(u[i],v[i]);
	}
	int le=0,ri=1e9,ans;
	while(le<=ri)
	{
		int mid=(le+ri)/2;
		if (check(mid))
		{
			ri=mid-1;
			ans=mid;
		}
		else le=mid+1;
	}
	printf("%d",ans);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 363ms, 内存消耗: 28380K, 提交时间: 2020-03-04 14:58:14

#include<bits/stdc++.h>
using namespace std;
const int NN=3e5+4;
struct edge
{
	int nxt,to,w;
}e[NN<<1];
struct node
{
	int x,y,lca,d;
}a[NN];
int fa[NN],h[NN],siz[NN],son[NN],top[NN],dfn[NN],head[NN],w[NN],num[NN],dis[NN],tim,tot,n,m,maxl=0,maxr=0;
void add(int x,int y,int z)
{
	e[++tot].nxt=head[x];
	e[tot].to=y;
	e[tot].w=z;
	head[x]=tot;
}
void dfs1(int u)
{
	h[u]=h[fa[u]]+1;
	siz[u]=1;
	int v;
	for(int i=head[u];i;i=e[i].nxt)
	if((v=e[i].to)!=fa[u])
	{
		fa[v]=u;
		w[v]=e[i].w;
		dis[v]=dis[u]+e[i].w;
		dfs1(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])
		son[u]=v;
	}
}
void dfs2(int u,int tp)
{
	top[u]=tp;
	dfn[++tim]=u;
	if(son[u])
	dfs2(son[u],tp);
	int v;
	for(int i=head[u];i;i=e[i].nxt)
	if((v=e[i].to)!=fa[u]&&v!=son[u])
	dfs2(v,v); 
}
int lca(int l,int r)
{
	while(top[l]!=top[r])
	{
		if(h[top[l]]<h[top[r]])
		swap(l,r);
		l=fa[top[l]];
	}
	return h[l]<=h[r]?l:r;
}
int check(int mid)
{
	int sum=0;
	memset(num,0,sizeof(num));
	for(int i=1;i<=m;i++)
	if(a[i].d>mid)
	{
		num[a[i].x]++;
		num[a[i].y]++;
		num[a[i].lca]-=2;
		sum++;
	 } 
	 for(int i=n;i>=1;i--)
	 {
	 	num[fa[dfn[i]]]+=num[dfn[i]];
	 	if(w[dfn[i]]>=maxr-mid&&num[dfn[i]]==sum)
	 	return 1;
	 }
	 return 0;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
		maxl=max(maxl,z);
	}
	dfs1(1);
	dfs2(1,1);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		a[i].lca=lca(a[i].x,a[i].y);
		a[i].d=dis[a[i].x]+dis[a[i].y]-2*dis[a[i].lca];
		maxr=max(maxr,a[i].d);
	}
	int l=maxr-maxl,r=maxr+1;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		r=mid;
		else
		l=mid+1;
	}
	printf("%d",l);
	return 0;
}

上一题