zoukankan      html  css  js  c++  java
  • CF1163F Indecisive Taxi Fee

    洛谷传送门 CF传送门

    Solution

    这题在暑假就讲了,等模拟赛出了还没做,只能亡羊补牢( ̄▽ ̄)"

    先考虑如果指定经过一条边的最短路怎么求?

    设此边为 ((u, v)) ,那么考虑从 (1)(n) 开始分别跑两次最短路 。设 (disS_i)(1)(i) 的最短路, (disT) 同理,那么答案就是 (min(disS_u+dis_{u,v}+disT_{v},disS_v+dis_{u,v}+disT_{u}))

    现在把修改分成4种:

    1. 修改的边不在 (1)(n) 的最短路上,边的长度变大了
    2. 修改的边不在 (1)(n) 的最短路上,边的长度变小了
    3. 修改的边在 (1)(n) 的最短路上,边的长度变小了
    4. 修改的边在 (1)(n) 的最短路上,边的长度变大了

    可得原最短路长度为 (disS_n) ,设修改的边为 ((u,v)) ,对于1, (disS_n) 就是答案;对于2,那么答案就是 (min{disS_n,disS_u+dis_{u,v}+disT_{v},disS_v+dis_{u,v}+disT_{u}}) ;对于3,答案是 (disS_n-dis_{u,v}+w)

    但是对于4,我们要进一步讨论。

    设最短路为 (G) ,则路径上的边为 (G_1,G_2,G_3,cdots ,G_k)

    对于每个不是 (G) 上的点, (1)(u) 的最短路必定会经过一段 (G) 的前缀(可以为空)。设 (L_u) 表示这个前缀,那么 (disS_u) 经过 (G_1.G_2,cdots G_{L_u})

    对于 (u)(n) 的最短路同理,可以得到 (R_u) 表示的后缀。

    回到问题4,就是求 (min(disS_n-dis_{u,v}+w,不经过修改这条边的最短路长度))

    那么怎么快速求出不经过 (G) 上某条边的最短路长度呢?

    我们可以使用线段树,区间 ((l,r)) 表示不经过 (G_l,cdots ,G_r) 这段的最短路长度。

    而此时 (L,R) 的用处就来了,我们可以拿经过 ((u,v)) 这条边的最短路长度更新 ((L_u+1,R_v),(L_v+1,R_u))

    时间复杂度: (O(nlog n+mlog n+qlog n))

    #include<bits/stdc++.h>
    #define ll long long
    #define ls rt<<1
    #define rs rt<<1|1
    
    using namespace std;
    const int N=2e5+10,M=2e5+10;
    const ll INF=1e18;
    struct id_edge{
        int u,v;
        ll w;
    }ie[M<<1];
    int n,m,q,dist;
    int in_dist[N],l[N],r[N];
    bool road[N];
    
    template <typename T> void read(T &x){
        int f=1;x=0;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        x*=f;
    }
    
    struct edge{
        int to,nxt,id;
        ll w;
    }e[M<<1];
    int head[N],cnt;
    inline void add(int id,int u,int v,ll w){
        e[++cnt].to=v;
        e[cnt].id=id;
        e[cnt].w=w;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    
    int lst_vis[N];
    ll dis_S[N],dis_T[N];
    struct node{
        int pos;
        ll dis;
        inline bool operator < (const node &x) const {
            return x.dis<dis;
        }
    };
    priority_queue<node> pq;
    inline void dijkstral(int s,ll dis[],int f=0){
        for(int i=1;i<=n;i++) dis[i]=INF;
        dis[s]=0;
        pq.push(node{s,0});
        while(!pq.empty()){
            node x=pq.top();pq.pop();
            int u=x.pos;
            if(x.dis>dis[u]) continue;
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(dis[v]>x.dis+e[i].w){
                    lst_vis[v]=e[i].id;
                    dis[v]=x.dis+e[i].w;
                    if(f==1&&!road[v]) l[v]=l[u];
                    if(f==2&&!road[v]) r[v]=r[u];
                    pq.push(node{v,dis[v]});
                }
            }
        }
    }
    
    inline void init_dist(){
        int now=1;
        road[now]=true;
        l[now]=r[now]=0;
        for(int i=1;now!=n;i++){
            int now_id=lst_vis[now];
            in_dist[now_id]=i;
            ++dist;
            now=ie[now_id].u^ie[now_id].v^now;
            road[now]=true;
            l[now]=r[now]=i;
        }
    }
    
    ll minn_dis[N<<4];
    void build(int rt,int l,int r){
        minn_dis[rt]=INF;
        if(l==r) return ;
        int mid=(l+r)>>1;
        build(ls,l,mid);build(rs,mid+1,r);
    }
    
    void update(int rt,int l,int r,int L,int R,ll k){
        if(L>R) return ;
        if(L<=l&&r<=R){
            minn_dis[rt]=min(minn_dis[rt],k);
            return ;
        }
        int mid=(l+r)>>1;
        if(L<=mid) update(ls,l,mid,L,R,k);
        if(R>mid) update(rs,mid+1,r,L,R,k);
    }
    
    ll query(int rt,int l,int r,int x){
        if(l==r) return minn_dis[rt];
        int mid=(l+r)>>1;
        ll res=minn_dis[rt];
        if(x<=mid) res=min(res,query(ls,l,mid,x));
        else res=min(res,query(rs,mid+1,r,x));
        return res;
    }
    
    int main(){
        // freopen("fee.in","r",stdin);
        // freopen("fee.out","w",stdout);
        read(n);read(m);read(q);
        for(int i=1;i<=m;i++){
            read(ie[i].u);read(ie[i].v);read(ie[i].w);
            add(i,ie[i].u,ie[i].v,ie[i].w);add(i,ie[i].v,ie[i].u,ie[i].w);
            in_dist[i]=-1;
        }
        dijkstral(n,dis_T);
        init_dist();
        dijkstral(1,dis_S,1);
        dijkstral(n,dis_T,2);
        build(1,1,dist);
        for(int i=1;i<=m;i++)
            if(in_dist[i]==-1){
                update(1,1,dist,l[ie[i].u]+1,r[ie[i].v],dis_S[ie[i].u]+ie[i].w+dis_T[ie[i].v]);
                update(1,1,dist,l[ie[i].v]+1,r[ie[i].u],dis_S[ie[i].v]+ie[i].w+dis_T[ie[i].u]);
            }
        for(int i=1,id,x;i<=q;i++){
            read(id);read(x);
            ll ans=dis_S[n];
            if(in_dist[id]==-1){
                if(x<ie[id].w){
                    ans=min(ans,dis_S[ie[id].u]+x+dis_T[ie[id].v]);
                    ans=min(ans,dis_S[ie[id].v]+x+dis_T[ie[id].u]);
                }
            }
            else{
                ans=ans-ie[id].w+x;
                if(x>ie[id].w){
                    ans=min(ans,query(1,1,dist,in_dist[id]));
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【Office】将一个excel文件中的表移动至另一个excel中
    【 DB_Oracle】impdp/expdp导入导出dmp文件
    【DB_Oracle】设置Oracle的监听和服务随 Linux开机自启
    【DB_Oracle】Centos中安装oracle11g R2
    【 DB_Oracle】Linux下启动Oracle服务和监听程序
    【OS_Linux】VMware中给CentOS磁盘扩容
    【 OS_Linux】WinSCP实现Windows与Linux间文件的传输
    【DB_Oracle】windows下安装Oracle 11g
    鼠标键盘失灵对策(Windows8.1)
    UNIX 高手的另外 10 个习惯
  • 原文地址:https://www.cnblogs.com/jasony/p/13928817.html
Copyright © 2011-2022 走看看