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 的物流公司完成阶段 性工作所需要的最短时间是多少?

输入输出格式

输入格式:

输入文件名为 transport.in。

第一行包括两个正整数 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
输出样例#1: 复制
11

说明

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

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

 

思路:这题好麻烦的说。。。我们先考虑m=1的情况,先对运输路线权值求和,再对运输路线权值求最大值,两者作差,得解。

当m!=1时,情况比较复杂,我们一步步分析。首先,因为要求最大值最小,所以我们考虑二分,令mid为当前二分的最大值,那么所有大于mid的路线都是不合法的,我们需要对路线进行删边。

 如果多条路线不合法且互不相交,那么我们无论删哪条边都不会使答案合法(想想看,为什么?)。如果存在一条边,它会被所有不合法的路线覆盖,那么它被删掉时才有可能使答案合法,答案合法

当且仅当删去这条边后使得原来最长的路线长度小于等于mid。因为,如果不把这条边删除,那么我们选择的另一条边一定没有被所有不合法的路线覆盖,那么删去后,至少会剩余一整条不合法的路线,

仍不能使答案合法。

求路径交,可以用树剖+线段树(奇慢) ,还可以用树上差分,如果把树上的点映射到DFS序中,那么会更快。由于这题数据范围巨恶心,所以只能用树上差分+DFS序。

至于lca,用树剖求或tarjan离线求。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=3e5+5;
const int M=3e5+5;
int read()
{
    int ret=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9')
    {ret=ret*10+c-'0';c=getchar();}
    return ret*f;
}
int n,m;
struct edge{
    int from,to,dis;
}e[M<<1];
int head[N],nxt[M<<1],tot=0;
void adde(int f,int t,int d)
{
    e[++tot]=(edge){f,t,d};
    nxt[tot]=head[f];
    head[f]=tot;
}
int fa[N],deep[N],siz[N],hson[N],top[N],dfn[N],rank[N],w[N],tim=0;
int tmp[N];
void dfs1(int t,int f)
{
    fa[t]=f;
    deep[t]=deep[f]+1;
    dfn[++tim]=t;
    for(int i=head[t];i;i=nxt[i])
    {
        int v=e[i].to;
        if(v!=f)
        {
            w[v]=e[i].dis;
            rank[v]=rank[t]+w[v];
            dfs1(v,t);
            siz[t]+=siz[v];
            if(!hson[t]||siz[v]>siz[hson[t]]) hson[t]=v;
        }
    }
}
void dfs2(int t,int tp)
{
    top[t]=tp;
    if(!hson[t]) return;
    dfs2(hson[t],tp);
    for(int i=head[t];i;i=nxt[i])
    {
        int v=e[i].to;
        if(v!=fa[t]&&v!=hson[t]) dfs2(v,v);
    }
}
int lca(int x,int y)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
        x=fa[fx],fx=top[x];
    }
    return deep[x]<deep[y]?x:y;
}
struct node{
    int from,to,lcaa,dis;
}p[M];
bool check(int mid)
{
    memset(tmp,0,sizeof(tmp));
    int cnt=0;
    int D=0;
    for(int i=1;i<=m;i++)
    {
        if(p[i].dis>mid)
        {
            cnt++;
            D=max(D,p[i].dis);
            tmp[p[i].from]++,tmp[p[i].to]++;
            tmp[p[i].lcaa]-=2;
        }
    }
    if(!cnt) return true;
    for(int i=n;i>=1;i--) tmp[fa[dfn[i]]]+=tmp[dfn[i]];
    for(int i=1;i<=n;i++)
    {
        if(tmp[i]==cnt&&D-w[i]<=mid) return true;
    }
    return false;
}
int main()
{
    n=read(),m=read();
    int a,b,c;
    for(int i=1;i<=n-1;i++)
    {
        a=read(),b=read(),c=read();
        adde(a,b,c);
        adde(b,a,c);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        a=read(),b=read();
        p[i].from=a,p[i].to=b;
        p[i].lcaa=lca(a,b);
        p[i].dis=rank[a]+rank[b]-2*rank[p[i].lcaa];
        
    }
    int l=0,r=1e9+7,mid;
    while(r-l>1)
    {
        mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%d
",r);
    return 0;
}
原文地址:https://www.cnblogs.com/loi-frank/p/7711007.html