[BZOJ4326] [NOIP2015] 运输计划

Description

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

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

小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去。显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰。

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

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

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

Input

第一行包括两个正整数n、m,表示L国中星球的数量及小P公司预接的运输计划的数量,星球从1到n编号。
接下来n-1行描述航道的建设情况,其中第i行包含三个整数ai, bi和ti,表示第i条双向航道修建在ai与bi两个星球之间,任意飞船驶过它所花费的时间为ti
接下来m行描述运输计划的情况,其中第j行包含两个正整数uj和vj,表示第j个运输计划是从uj号星球飞往vj号星球。

Output

共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。

Sample Input

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

Sample Output

11

HINT

【样例说明】
将第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。

【数据规模与约定】
所有测试数据的范围和特点如下表所示

题目分析:

因为求最小的最大值,所以就二分答案了。
我们需要在一条边权变成0后 所有的计划都小于mid .
于是我们贪心的 找到边权最大的一条边 并且保证这条边在所有时间大于mid的计划里
那么 我们用树上差分 标记一下每条边都在多少个时间大于mid的计划里
最后找到边后判断一下就好了

卡常失败QAQ TLE%5

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int net[600100],head[300100],to[600100],v[600100];
int tot;
int read()
{
    int nmp=0;
    char c;
    c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c<='9'&&c>='0')
        nmp=nmp*10+(c-'0'),c=getchar();
    return nmp;
}
void add(int x,int y,int c)
{
    net[++tot]=head[x];
    to[tot]=y;
    v[tot]=c;
    head[x]=tot;
}
int dx[300100],dy[300100];
int deep[300100],fa[300100][22],val[300100],dis[300100];
int que[300100];
int LCA[300100],sum[300100];
int LOG=1;
void dfs(int x,int temp)
{
    deep[x]=deep[temp]+1;
    fa[x][0]=temp;
    for(int i=1;fa[x][i-1];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    que[++que[0]]=x;
    for(int i=head[x];i;i=net[i])
        if(to[i]!=temp)
        {
            dis[to[i]]=dis[x]+v[i];
            val[to[i]]=v[i];
            dfs(to[i],x);
        }
}
int lca(int x,int y)
{
    int temp=LOG;
    if(deep[x]<deep[y]) swap(x,y);    
    while(temp>=0)
    {
        if(deep[fa[x][temp]]>=deep[y])
            x=fa[x][temp];
        temp--;
    }
    if(x==y) return x;
    temp=LOG;
    while(temp>=0)
    {
        if(fa[x][temp]!=fa[y][temp])
            x=fa[x][temp],y=fa[y][temp];
        temp--;
    }
    return fa[x][0];
}
int color[300100];
int check(int mid)
{
    memset(color,0,sizeof color);
    int tmp=0,maxx=0;
    for(int i=1;i<=m;i++)
        if(sum[i]>mid) 
            maxx=max(maxx,sum[i]),tmp++,color[dx[i]]++,color[dy[i]]++,color[LCA[i]]-=2;
    if(tmp==0) return 1;
    for(int i=que[0];i>=1;i--)
    {
        color[fa[que[i]][0]]+=color[que[i]];
        if(color[que[i]]==tmp&&maxx-val[que[i]]<=mid) return 1;
    }
    return 0;
}
int find()
{
    int l=0,r=500000000;
    int mid=(l+r)>>1;
    int tmp;
    while(l<r)
    {
        if(check(mid)) r=mid,tmp=mid;
        else l=mid+1;
        mid=(l+r)>>1;        
    }
    return tmp;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int x,y,c;
        x=read();y=read();c=read();
        add(x,y,c),add(y,x,c);
    }
    dfs(1,0);
    int k=1;
    while(k<n) k<<=1,LOG++;
    for(int i=1;i<=m;i++)
    {
        dx[i]=read();dy[i]=read();
        LCA[i]=lca(dx[i],dy[i]);
        sum[i]=dis[dx[i]]+dis[dy[i]]-2*dis[LCA[i]];
    }
    printf("%d",find());
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注