删边最短路

今天写题的时候做到一个非常牛的东西。

给你一个图,\(q\) 次问你如果删掉一条边,\(1\)\(n\) 的最短路会变成多少。

首先搞出来 \(1\) 出发的最短路树,然后如果这条边根本不在这棵树上,显然没有任何影响。

如果在的话,我们必然要绕路了。

给出一个性质:我们选择绕的路至多经过一条原来的非树边。

简单思考一下这是为什么。首先我们假设经过了至少两条非树边。

我们任意选取其中的两条。如果这两条有一条根本就没有跨过删除的边,显然这条边是不优的。否则,因为这两条都是非树边,我们在经过一条边之后,一定存在另一个更加不劣的方式回到主干道上。

所以我们只需要对于每一条边算一下它贡献的树边区间,用一个线段树维护即可。这个贡献的区间的两个端点其实就是在 \(1,n\) 最短路树上分别与这条边两个端点的 lca。注意这两颗最短路树上的 \(1\)\(n\) 的最短路必须相同

有例题 CF1163F。

就这个题首先我们可以把 \(1\)\(n\) 的最短路摘出来,然后我们称之为关键边。

不在关键边上的修改是好处理的,这里留给读者思考。

在关键边上并且改小边权也是好处理的,这里仍然留给读者思考。

下文只处理剩下的一种情况。

我们进行最终形态宏观考虑,发现最终的路径要么不变,要么不经过改的边(因为如果经过一定是走原路径更优)。

路径不变仍然是简单的。

我们给出性质,若不经过改的边,则一定经过一条不在最短路树上的边。

那么相当于对于一条非树边,我们先从 \(1\) 走到一个端点,再走过这条边,最后从另一个端点走到 \(n\)

显然地,我们的这条路径会共用 \(1\)\(n\) 初始最短路的一段前后缀(可以为空)。于是这条边的贡献是一个区间。直接线段树区间 cmin,单点查值即可。

放一下代码:

#include<bits/stdc++.h>
#define int long long
#define N 200005
#define mod 998244353
#define pii pair<int,int>
#define x first
#define y second
#define pct __builtin_popcount
#define mpi make_pair
// #define inf 2e18
using namespace std;
int T=1,n,m,q,cnt,dis[2][N],pre[2][N],id[N],nw[N],val[N];
int inf=2e18;
pii ed[N];
bool st[N],vis[N],tr[N];
struct edge{
    int x,y,id;
};
vector<edge>e[N];
struct node{
    int d,u;
    bool operator<(const node &t)const{
        return d>t.d;
    }
};
struct ds{
    vector<int>g[N];
    int dep[N],fa[N],siz[N],son[N],top[N];
    void adde(int a,int b){
        g[a].push_back(b);
    }
    void dfs1(int u,int f){
        dep[u]=dep[f]+1;
        fa[u]=f;
        siz[u]=1;
        for(auto j:g[u]){
            if(j==fa[u])continue;
            dfs1(j,u);
            siz[u]+=siz[j];
            if(siz[j]>siz[son[u]])son[u]=j;
        }
    }
    void dfs2(int u,int f){
        top[u]=f;
        if(son[u])dfs2(son[u],f);
        for(auto j:g[u]){
            if(j==fa[u]||j==son[u])continue;
            dfs2(j,j);
        }
    }
    int get_lca(int a,int b){
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            a=fa[top[a]];
        }
        return dep[a]<dep[b]?a:b;
    }
}t1,t2;
void add(int a,int b,int c,int d){
    e[a].push_back({b,c,d});
}
void dij(int op,int s){
    memset(dis[op],0x3f,sizeof dis[op]);
    memset(st,0,sizeof st);
    priority_queue<node>q;
    dis[op][s]=0;
    q.push({dis[op][s],s});
    if(!op){
        while(!q.empty()){
            auto t=q.top();
            q.pop();
            int u=t.u;
            if(st[t.u])continue;
            st[t.u]=1;
            for(auto it:e[u]){
                int j=it.x,w=it.y;
                if(dis[op][j]>dis[op][u]+w){
                    dis[op][j]=dis[op][u]+w;
                    pre[op][j]=u;
                    q.push({dis[op][j],j});
                }
            }
        }
        int cur=n;
        while(cur){
            vis[cur]=1;
            id[cur]=++cnt;
            cur=pre[op][cur];
        }
        for(int i=1;i<=n;i++){
            if(id[i]){
                id[i]=cnt-id[i]+1;
                nw[id[i]]=i;
            }
        }
    }
    else{
        while(!q.empty()){
            auto t=q.top();
            q.pop();
            int u=t.u;
            if(st[t.u])continue;
            st[t.u]=1;
            for(auto it:e[u]){
                int j=it.x,w=it.y;
                if(dis[op][j]>dis[op][u]+w){
                    dis[op][j]=dis[op][u]+w;
                    pre[op][j]=u;
                    q.push({dis[op][j],j});
                }
                else if(dis[op][j]==dis[op][u]+w&&vis[u]){
                    pre[op][j]=u;
                }
            }
        }
    }
}
struct sgt{
    int tr[N<<2],tag[N<<2];
    void pushup(int u){
        tr[u]=min(tr[u<<1],tr[u<<1|1]);
    }
    void build(int u,int l,int r){
        tag[u]=inf;
        if(l==r){
            tr[u]=inf;
            return;
        }
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
    void maketag(int u,int v){
        tr[u]=min(tr[u],v);
        tag[u]=min(tag[u],v);
    }
    void pushdown(int u){
        if(tag[u]==inf)return;
        maketag(u<<1,tag[u]);
        maketag(u<<1|1,tag[u]);
        tag[u]=inf;
    }
    void modify(int u,int l,int r,int L,int R,int v){
        if(L>R)return;
        if(l>=L&&r<=R){
            maketag(u,v);
            return;
        }
        int mid=l+r>>1;
        pushdown(u);
        if(L<=mid)modify(u<<1,l,mid,L,R,v);
        if(R>mid)modify(u<<1|1,mid+1,r,L,R,v);
        pushup(u);
    }
    int qry(int u,int l,int r,int L,int R){
        if(L>R)return inf;
        if(l>=L&&r<=R)return tr[u];
        int mid=l+r>>1;
        int res=inf;
        pushdown(u);
        if(L<=mid)res=min(res,qry(u<<1,l,mid,L,R));
        if(R>mid)res=min(res,qry(u<<1|1,mid+1,r,L,R));
        return res;
    }
}sgt;
void solve(int cs){
    if(!cs)return;
    cin>>n>>m>>q;
    for(int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c,i);
        add(b,a,c,i);
        val[i]=c;
        ed[i]=mpi(a,b);
    }
    dij(0,1);
    dij(1,n);
    for(int i=1;i<=n;i++){
        for(auto it:e[i]){
            int j=it.x,w=it.y,d=it.id;
            if(pre[0][j]==i&&dis[0][i]+w==dis[0][j]&&id[i]&&id[j]){
                tr[d]=1;
            }
        }
    }
    for(int i=2;i<=n;i++){
        t1.adde(pre[0][i],i);
    }
    for(int i=1;i<n;i++){
        t2.adde(pre[1][i],i);
    }
    t1.dfs1(1,0);
    t1.dfs2(1,1);
    t2.dfs1(n,0);
    t2.dfs2(n,n);
    sgt.build(1,1,cnt);
    for(int i=1;i<=m;i++){
        int a=ed[i].x,b=ed[i].y,c=val[i];
        if(tr[i])continue;
        int L=id[t1.get_lca(a,n)],R=id[t2.get_lca(1,b)];
        if(L>=R)swap(a,b);
        L=id[t1.get_lca(a,n)],R=id[t2.get_lca(1,b)];
        sgt.modify(1,1,cnt,L,R-1,c+dis[0][a]+dis[1][b]);
    }
    while(q--){
        int t,x;
        cin>>t>>x;
        if(!tr[t]){
            if(x>=val[t]){
                cout<<dis[0][n]<<'\n';
            }
            else{
                int a=ed[t].x,b=ed[t].y;
                cout<<min({dis[0][n],dis[0][a]+x+dis[1][b],dis[0][b]+x+dis[1][a]})<<'\n';
            }
        }
        else{
            if(x<=val[t]){
                cout<<dis[0][n]-val[t]+x<<'\n';
            }
            else{
                int a=ed[t].x,b=ed[t].y;
                cout<<min(dis[0][n]-val[t]+x,sgt.qry(1,1,cnt,min(id[a],id[b]),min(id[a],id[b])))<<'\n';
            }
        }
    }
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	// cin>>T;
	// init();
	for(int cs=1;cs<=T;cs++){
		solve(cs);
	}
	return 0;
}
posted @ 2025-09-15 10:30  zxh923  阅读(108)  评论(2)    收藏  举报