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

    题目描述

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


    通过对题目的大致分析可以得出:

    改造的边一定在最长的航线上。设最长航线长度为p,改造的边为e,不包含边e的航线中最长的一条为q,那么改造边e的答案就是:Max(p-e,q)。然后我们枚举最长航线上的每一条边,得到其Max(p-e,q),最小的那个就是答案。但关键就在于如何得到q。

    我们可以处理出对于每一条边e,不包含e的最长航线是多长。设这个值为f(e)

    显然枚举e太费时,我们可以枚举航线。

    对于每条航线p,我们可以处理出航线以外的边的f值:f(e)=Max(f(e),length(p))。但如果一个一个改就很麻烦,所以我们需要引入一个支持区间最大值修改和单点查询的数据结构:线段树。

    要使用线段树,我们先对原树进行重链剖分。显然对于一条航线,它必定由若干段连续的dfs序组成。所以我们先从航线两端往上跳,记录下跳过的dfs序区间。于是我们可以得到若干个不相交的dfs序区间。对其进行排序后,我们得出这些区间在[1,n]的补集,用线段树进行区间最大值修改即可,修改的值就是当前航线的长度。那么线段树上每个点的值就是不包含这条边的航线最大值。

    最后我们再枚举最长航线上的每一条边,进行单点查询,根据之前的分析得出答案:ans=Min( Max(p-e,q) )。

    复杂度应该是Nloglog级别,可以通过本题。

    * 为了卡常,计算路径长度可以用树状数组。

    * 事先把边权转化为点权(基本功)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 300001
    using namespace std;
    
    struct edge{
        int to,dis,next;
        edge(){}
        edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
    }e[maxn<<1];
    int head[maxn],k;
    int n,m,val[maxn];
    
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]),head[u]=k++; }
    
    int size[maxn],fa[maxn],son[maxn],dep[maxn];
    int dfn[maxn],id[maxn],top[maxn],tot;
    void dfs_getson(int u){
        size[u]=1;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==fa[u]) continue;
            fa[v]=u,dep[v]=dep[u]+1;
            dfs_getson(v);
            size[u]+=size[v];
            if(size[v]>size[son[u]]) son[u]=v;
        }
    }
    void dfs_rewrite(int u,int tp){
        top[u]=tp,dfn[u]=++tot,id[tot]=u;
        if(son[u]) dfs_rewrite(son[u],tp);
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v!=fa[u]&&v!=son[u]) dfs_rewrite(v,v);
        }
    }
    inline void endow(){
        for(register int i=0;i<k;i+=2){
            int u=e[i].to,v=e[i^1].to;
            if(dep[u]>dep[v]) swap(u,v);
            val[v]=e[i].dis;
        }
    }
    
    int sum[maxn];
    inline int lowbit(const int &x){ return x&(-x); }
    inline int add(int x,const int &val){ for(;x<=n;x+=lowbit(x)) sum[x]+=val; }
    inline void create(){ for(register int i=1;i<=n;i++) add(i,val[id[i]]); }
    inline int getsum(int x){ int ans=0; for(;x;x-=lowbit(x)) ans+=sum[x]; return ans; }
    inline int query(int l,int r){ return getsum(r)-getsum(l-1); }
    
    struct node{
        int l,r,mmax,f;
    }t[maxn<<2];
    inline void down(const int &d){
        t[d<<1].mmax=max(t[d<<1].mmax,t[d].f),t[d<<1|1].mmax=max(t[d<<1|1].mmax,t[d].f);
        t[d<<1].f=max(t[d<<1].f,t[d].f),t[d<<1|1].f=max(t[d<<1|1].f,t[d].f);
        t[d].f=0;
    }
    void build(int d,int l,int r){
        t[d].l=l,t[d].r=r;
        if(l==r) return;
        int mid=l+r>>1;
        build(d<<1,l,mid),build(d<<1|1,mid+1,r);
    }
    void change(int d,const int &l,const int &r,const int &val){
        if(l>r) return;
        if(l<=t[d].l&&t[d].r<=r){ t[d].mmax=max(t[d].mmax,val),t[d].f=max(t[d].f,val); return; }
        if(t[d].f) down(d);
        int mid=t[d].l+t[d].r>>1;
        if(l<=mid) change(d<<1,l,r,val);
        if(r>mid) change(d<<1|1,l,r,val);
        t[d].mmax=max(t[d<<1].mmax,t[d<<1|1].mmax);
    }
    int getmax(int d,const int &x){
        if(t[d].l==t[d].r) return t[d].mmax;
        if(t[d].f) down(d);
        int mid=t[d].l+t[d].r>>1;
        if(x<=mid) return getmax(d<<1,x);
        else return getmax(d<<1|1,x);
    }
    
    int maxl,maxr,mmax;
    int l[maxn],r[maxn],seg[maxn],d=0;
    inline bool cmp(const int &x,const int &y){ return l[x]<l[y]; }
    inline int getsum_path(int u,int v){
        int ans=0;
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            ans+=query(dfn[top[v]],dfn[v]);
            v=fa[top[v]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        if(u!=v) ans+=query(dfn[u]+1,dfn[v]);
        return ans;
    }
    inline void update(int u,int v,int w){
        d=0;
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            l[++d]=dfn[top[v]],r[d]=dfn[v];
            v=fa[top[v]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        l[++d]=dfn[u]+1,r[d]=dfn[v];
        for(register int i=1;i<=d;i++) seg[i]=i;
        sort(seg+1,seg+1+d,cmp);
        if(l[seg[1]]>1) change(1,1,l[seg[1]]-1,w);
        if(r[seg[d]]<tot) change(1,r[seg[d]]+1,tot,w);
        for(register int i=1;i<d;i++) change(1,r[seg[i]]+1,l[seg[i+1]]-1,w);
    }
    inline int getans(int u,int v){
        int ans=0x3f3f3f3f;
        if(u==v) return 0;
        while(u!=v){
            if(dep[u]>dep[v]) swap(u,v);
            ans=min(ans,max(mmax-val[v],getmax(1,dfn[v]))),v=fa[v];
        }
        return ans;
    }
    
    int main(){
        memset(head,-1,sizeof head);
        n=read(),m=read();
        for(register int i=1;i<n;i++){
            int u=read(),v=read(),w=read();
            add(u,v,w),add(v,u,w);
        }
        dfs_getson(1),dfs_rewrite(1,1),endow();
        build(1,1,tot),create();
        for(register int i=1;i<=m;i++){
            int u=read(),v=read(),sum=getsum_path(u,v); update(u,v,sum);
            if(sum>mmax) mmax=sum,maxl=u,maxr=v;
        }
        printf("%d
    ",getans(maxl,maxr));
        return 0;
    }
    
  • 相关阅读:
    Windows Server 2012配置开机启动项
    Windows Server 2019 SSH Server
    NOIP2017 senior A 模拟赛 7.7 T1 棋盘
    Noip 2015 senior 复赛 Day2 子串
    Noip 2015 senior复赛 题解
    Noip 2014 senior Day2 解方程(equation)
    Noip 2014 senior Day2 寻找道路(road)
    Noip 2014 senior Day2 无线网络发射器选址(wireless)
    Noip2014senior复赛 飞扬的小鸟
    Noip 2014 senior 复赛 联合权值(link)
  • 原文地址:https://www.cnblogs.com/akura/p/11053532.html
Copyright © 2011-2022 走看看