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(n\log n+m\log n+q\log 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\n",ans);
    }
    return 0;
}
posted @ 2020-11-04 21:43  jasony_sam  阅读(129)  评论(0编辑  收藏  举报