zoukankan      html  css  js  c++  java
  • [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 的物流公司完成阶段 性工作所需要的最短时间是多少?

    $Solution:$

    其实挺简单的……跟保卫王国什么的没法比……

    题意就是给你几条树上路径,有一次删除边权的机会,最小化它们的最大长度。“最大值最小”显然二分啊。

    考虑怎么check,首先如果二分出的$ans ge $最长路径长度那么一定是合法的,不过没什么用,因为完全可以把二分右端点设为最长路径长度。

    我们可以无视长度$leq ans$的路径,那么接下来要做的,就是利用删除边权操作在答案中消去最长路径长度$-ans$这么大(设为w)的长度。在剩下的路径中,如果存在一条这些路径的公共边满足边权$ge w$,就可以判定为合法的。

    求路径的公共边可以转化为求树边覆盖次数,树上差分板子,注意对于边的差分是x++,y++,lca-=2。

    然后路径长什么的直接lca求解即可。

    由于它是一道有尊严的D2T3,所以肯定会防AK。卡一下二分左右边界可以苟过去= =。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define pa pair<int,int>
    #define re register
    using namespace std;
    
    const int L=1<<20|1;
    char buffer[L],*S,*T;
    #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=3e5+5;
    int n,m,to[N<<1],head[N],nxt[N<<1],tot,w[N<<1];
    int size[N],son[N],top[N],fa[N],dep[N],dis[N];
    pa p[N];
    int D[N],_lca[N],dif[N],maxw;
    inline void add(int x,int y,int z)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
        w[tot]=z;
    }
    void dfs1(int x,int f)
    {
        fa[x]=f;dep[x]=dep[f]+1;size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==f)continue;
            dis[y]=dis[x]+w[i];
            dfs1(y,x);
            size[x]+=size[y];
            if(size[y]>size[son[x]])son[x]=y;
        }
    }
    void dfs2(int x,int Top)
    {
        top[x]=Top;
        if(son[x])dfs2(son[x],Top);
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(top[y])continue;
            dfs2(y,y);
        }
    }
    inline int lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        return x;
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x])continue;
            dfs(y);
            dif[x]+=dif[y];
        }
    }
    bool judge(int x,int cnt,int len)
    {
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x])continue;
            if(dif[y]==cnt&&w[i]>=len)return 1;
            if(judge(y,cnt,len))return 1;
        }
        return 0;
    }
    
    inline bool check(int val)
    {
        if(maxw<=val)return 1;
        for(re int i=1;i<=n;i++)dif[i]=0;
        int cnt=0;
        for(re int i=1;i<=m;i++)
        {
            if(D[i]<=val)continue;
            cnt++;
            dif[p[i].first]++;dif[p[i].second]++;
            dif[_lca[i]]-=2;
        }
        dfs(1);
        return judge(1,cnt,maxw-val);
    }
    
    int main()
    {
        n=read();m=read();
        int maxe=0;
        for(re int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            add(x,y,z);add(y,x,z);
            maxe=max(maxe,z);
        }
        dfs1(1,0);dfs2(1,1);
    
        for(re int i=1;i<=m;i++)
        {
            int x=read(),y=read(),LCA=lca(x,y);
            p[i]=make_pair(x,y);
            D[i]=dis[x]+dis[y]-2*dis[LCA];
            maxw=max(maxw,D[i]);
            _lca[i]=LCA;
        }
        int l=maxw-maxe,r=maxw,ans=r;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Windows Server 2012上PHP运行环境搭建的简易教程(Win08适用)
    Windows 8.1 系统ISO镜像下载或自Win8应用商店升级方法
    dojo布局(layout)
    dojo创建tree
    Postgres SQL学习笔记
    PostGIS ShapeFile 导入数据
    利用 PortableBasemapServer 发布地图服务
    Fortran 笔记
    ArcMap 操作笔记
    gdal编译C#开发版本
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11808751.html
Copyright © 2011-2022 走看看