zoukankan      html  css  js  c++  java
  • [NOIP2015]运输计划

    [NOIP2015]运输计划https://www.luogu.org/problemnew/show/P2680

    题目背景

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

    题目描述

    (L) 国有 (n) 个星球,还有 (n-1) 条双向航道,每条航道建立在两个星球之间,这 (n-1) 条航道连通了 (L) 国的所有星球。
    (P) 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 (u_i) 号星球沿最快的宇航路径飞行到 (v_i) 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 (j),任意飞船驶过它所花费的时间为 (t_j),并且任意两艘飞船之 间不会产生任何干扰。
    为了鼓励科技创新, (L) 国国王同意小 (P) 的物流公司参与 (L) 国的航道建设,即允许小 (P) 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
    在虫洞的建设完成前小 (P) 的物流公司就预接了 (m) 个运输计划。在虫洞建设完成后, 这 (m) 个运输计划会同时开始,所有飞船一起出发。当这 (m) 个运输计划都完成时,小 (P) 的 物流公司的阶段性工作就完成了。
    如果小 (P) 可以自由选择将哪一条航道改造成虫洞,试求出小 (P) 的物流公司完成阶段性工作所需要的最短时间是多少?

    输入格式:

    输入文件名为 (transport.in)
    第一行包括两个正整数 (n、m),表示 (L) 国中星球的数量及小 (P) 公司预接的运输计划的数量,星球从 (1)(n) 编号。
    接下来 (n-1) 行描述航道的建设情况,其中第 (i) 行包含三个整数 (a_i, b_i)(t_i)表示第
    (i) 条双向航道修建在 (a_i)(b_i) 两个星球之间,任意飞船驶过它所花费的时间为 (t_i)
    接下来 (m) 行描述运输计划的情况,其中第 (j) 行包含两个正整数 (u_j)(v_j),表示第 (j)个 运输计划是从 (u_j) 号星球飞往 (v_j) 号星球。

    输出格式:

    输出共(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

    说明

    (n,m<=300000)
    (1<=a_i,b_i,u_j,v_j<=n)
    (t_i<=1000)
    请注意常数因子带来的程序效率上的影响。


    由题面信息可知,我们要删除一条边,使所有计划用时的最大值最小.
    不难猜出是要二分答案的.
    左端点(L=0),右段点(R=)所有计划中用时的最大值(Maxlen).
    因此先预处理出每个运输计划的用时[求LCA]
    二分出一个(mid)
    那么所有用时大于(mid)的计划都是不合法的,这些路径必须作出改动,因此删掉的边应为它们的公共边.
    如果树剖维护每条边被不合法计划经过的次数,
    那么被删的那条边一定被每个不合法计划都经过
    找出这些边
    对于某条边,设边权为(val),并检验

    [Maxlen-val<=mid ]

    如果有一条边能满足条件,则有解,返回(true)
    否则返回(false)
    建议:
    树剖用树状数组,线段树常数大卡掉(5)分,树状数组开(O2)可过.

    #define RG register
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=3e5+5;
    inline int read()
    {
        RG int x=0,w=1;RG char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    int n,m,ct,cnt,L,R,Ans;
    int last[N],dep[N],top[N],son[N],dfn[N],size[N],f[N][25],dist[N][25],sum[N];
    struct edge{int to,next,w;}e[N<<1];
    struct node{int val,u,v;}lca[N];
    inline bool cmp(node a,node b){return a.val<b.val;}
    inline int lowbit(int x){return (-x)&x;}
    inline void insert(int u,int v,int w)
    {
        e[++cnt]=(edge){v,last[u],w};last[u]=cnt;
        e[++cnt]=(edge){u,last[v],w};last[v]=cnt;
    }
    void dfs1(int now)
    {
        size[now]=1;
        for(int i=last[now];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v==f[now][0])continue;
            dep[v]=dep[now]+1;
            f[v][0]=now;
            dist[v][0]=e[i].w;
            dfs1(v);
            size[now]+=size[v];
            if(size[v]>size[son[now]])son[now]=v;
        }
    }
    void dfs2(int now,int Top)
    {
        top[now]=Top;dfn[now]=++ct;
        if(son[now])dfs2(son[now],Top);
        for(RG int i=last[now];i;i=e[i].next)
        {
            RG int v=e[i].to;
            if(v==f[now][0]||v==son[now])continue;
            dfs2(v,v);
        }
    }
    inline void init()
    {
        dep[1]=1;
        dfs1(1);
        dfs2(1,1);
        for(RG int j=1;j<=20;j++)
            for(RG int i=1;i<=n;i++)
            {
                f[i][j]=f[f[i][j-1]][j-1];
                dist[i][j]=dist[i][j-1]+dist[f[i][j-1]][j-1];
            }
    }
    inline int Lca(int x,int y)
    {
        RG int Sum=0;
        if(dep[y]>dep[x])swap(x,y);
        for(RG int i=20;i>=0;i--)if(f[x][i]&&dep[f[x][i]]>=dep[y])Sum+=dist[x][i],x=f[x][i];
        if(x==y)return Sum;
        for(RG int i=20;i>=0;i--)
            if(f[x][i]&&f[y][i]&&f[x][i]!=f[y][i])
            {
                Sum+=dist[x][i]+dist[y][i];
                x=f[x][i];y=f[y][i];
            }
        Sum+=dist[x][0]+dist[y][0];
        return Sum;
    }
    inline void Modify(int x,int k)
    {
        while(x<=n)sum[x]+=k,x+=lowbit(x);
    }
    inline int Query(int x)
    {
        RG int Ans=0;
        while(x)Ans+=sum[x],x-=lowbit(x);
        return Ans;
    }
    inline void Modify_Tree(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            Modify(dfn[top[x]],1);Modify(dfn[x]+1,-1);
            x=f[top[x]][0];
        }
        if(dep[x]>dep[y])swap(x,y);
        if(x!=y)Modify(dfn[x]+1,1),Modify(dfn[y]+1,-1);
    }
    inline bool check(int k)
    {
        memset(sum,0,sizeof(sum));
        RG int Num=0;
        for(RG int i=m;i>=1;i--)
        {
            if(lca[i].val>k)Num++,Modify_Tree(lca[i].u,lca[i].v);
            else break;
        }
        for(RG int i=1;i<=n;i++)if(Query(dfn[i])==Num&&lca[m].val-dist[i][0]<=k)return true;
        return false;
    }
    int main()
    {
        n=read();m=read();
        for(RG int i=1;i<n;i++)
        {
            RG int a=read(),b=read(),c=read();
            insert(a,b,c);
        }
        init();
        for(RG int i=1;i<=m;i++)
        {
            lca[i].u=read();lca[i].v=read();
            lca[i].val=Lca(lca[i].u,lca[i].v);
        }
        sort(lca+1,lca+m+1,cmp);
        R=lca[m].val;
        while(L<=R)
        {
            RG int mid=(L+R)>>1;
            if(check(mid))Ans=mid,R=mid-1;
            else L=mid+1;
        }
        printf("%d
    ",Ans);
        return 0;
    }
    
  • 相关阅读:
    Another kind of Fibonacci(hdu3306)
    Robot(hdu5673)
    The Luckiest number(hdu2462)
    Description has only two Sentences(hdu3307)
    codeforces(Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) )(C,D)
    Abelian Period
    Brute-force Algorithm(hdu3221)
    1046:Square Number
    Harry Potter and the Hide Story(hdu3988)
    C. Journey
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/8635457.html
Copyright © 2011-2022 走看看