Wannafly挑战赛2D Delete 删点最短路(拓扑序+最短路+线段树)

题目

(Delete)https://ac.nowcoder.com/acm/problem/14293

题目描述

给定一张n个点,m条边的带权有向无环图,同时给定起点S和终点T,一共有q个询问,每次询问删掉某个点和所有与它相连的边之后S到T的最短路,询问之间互相独立(即删除操作在询问结束之后会立即撤销),如果删了那个点后不存在S到T的最短路,则输出-1。

输入描述:

第一行四个正整数表示n,m,S,T,意义如题所述;
接下来m行每行三个正整数x[i],y[i],z[i],表示有一条x[i]到y[i]的有向边,权值为z[i];
第m+1行一个正整数q表示询问次数;
接下来q行每行一个正整数a[i]表示这次询问要删除点a[i]。
n,q <= 10^5
m <= 2*10^5
z[i] <= 10^9

输出描述:

q行每行一个数输出答案,如果删了这个点后不存在S到T的最短路,输出-1

输入

6 7 1 5
1 2 2
2 3 4
3 4 3
4 5 5
3 5 9
1 6 10
6 5 13
4
3
4
2
6

输出

23
15
23
14

思路

因为是DGA,那么就可以拓扑排序,每个点都有一个拓扑序,那么x点的拓扑序Top[x],假如x点被删除,那么经过x的最短路,一定是经过了一条边u-v
Top[u]<Top[x]&&Top[v]>Top[x]并且d1[u]!=inf&&d2[v]!=inf的最短路。我们枚举所有的边,并且把区间修改[Top[u]+1,Top[v]1]的最小值修改为d1[u]+Wuv+d2[v]
对于一个点区间查询就可以了。这里我们一次查询把所有的标记下转到叶子节点就可以了。

#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#define pLL pair<long long, long long>
#define LL long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)

using namespace std;

char buf[1<<20],*p1=buf,*p2=buf;
inline LL read(){
    char c=getchar();LL x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

struct Edge {
    int from, to;
    LL w;
    int nxt;
} e[2000005], e2[2000005];
int head[100005], head2[100005], cut=0, cut2=0;

void Addedge(int x, int y, LL w){
    e[++cut]={x, y, w, head[x]}; head[x]=cut;
}

void Addedgef(int x, int y, LL w){
    e2[++cut2]={x, y, w, head2[x]}; head2[x]=cut2;
}

priority_queue<pLL> q;
int vis[100005];
void DP(int s, LL d[], int head[], Edge e[]){
    q.push({d[s]=0, s});
    while(!q.empty()){
        pLL now=q.top(); q.pop();
        int u=now.second;
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u]; i; i=e[i].nxt){
            int to=e[i].to; LL w=e[i].w;
            if(d[to]>d[u]+w){
                d[to]=d[u]+w;
                q.push({-d[to], to});
            }
        }
    }
}

int d[100005];
int id[100005], fid[100005], pos=0;
queue<int> qq;
void Top(int s, int n){
    for(int i=1; i<=n; i++){
        if(d[i]==0){
            qq.push(i);
        }
    }
    while(!qq.empty()){
        int now=qq.front(); qq.pop();
        id[now]=++pos; fid[pos]=now;
        for(int i=head[now]; i; i=e[i].nxt){
            d[e[i].to]--;
            if(!d[e[i].to]){
                qq.push(e[i].to);
            }
        }
    }
}

LL ans[100005];
LL d1[100005], d2[100005];
LL inf;
struct Tree{
    LL mi[100005*4];
    void init(){
        memset(mi, 0x3f, sizeof(mi));
        inf=mi[0];
    }
    void up_data(int rt, int l, int r, int L, int R, LL w){
        if(l==L&&r==R){
            mi[rt]=min(mi[rt], w);
            return ;
        }
        int mid=l+r>>1;
        if(R<=mid) up_data(rt<<1, l, mid, L, R, w);
        else if(L>mid) up_data(rt<<1|1, mid+1, r, L, R, w);
        else up_data(rt<<1, l, mid, L, mid, w), up_data(rt<<1|1, mid+1, r, mid+1, R, w);
    }
    void qurey(int rt, int l, int r, LL w){
        if(l==r){
            if(d1[fid[l]]==inf||d2[fid[l]]==inf) ans[fid[l]]=w;
            else ans[fid[l]]=mi[rt];
            return ;
        }
        else{
            int mid=l+r>>1;
            mi[rt<<1]=min(mi[rt<<1], mi[rt]);
            mi[rt<<1|1]=min(mi[rt<<1|1], mi[rt]);
            qurey(rt<<1, l, mid, w); qurey(rt<<1|1, mid+1, r, w);
        }
    }
}T;

int main() {
    int n=read(), m=read(), s=read(), t=read(), x, y;
    for(int i=1; i<=m; i++){
        x=read(), y=read();
        LL w=read();
        d[y]++;
        Addedge(x, y, w);
        Addedgef(y, x, w);
    }
    memset(d1, 0x3f, sizeof(d1));
    memset(vis, 0, sizeof(vis));
    DP(s, d1, head, e);
    memset(d2, 0x3f, sizeof(d2));
    memset(vis, 0, sizeof(vis));
    DP(t, d2, head2, e2);
    Top(s, n);
    T.init();
    for(int i=1; i<=m; i++){
        int x=e[i].from, y=e[i].to;
        if(id[x]!=id[y]-1&&d1[x]!=inf&&d2[y]!=inf){
            T.up_data(1, 1, n, id[x]+1, id[y]-1, d1[x]+d2[y]+e[i].w);
        }
    }
    T.qurey(1, 1, n, d1[t]);
    int q=read();
    while(q--){
        int x=read();
        printf("%lld\n", (ans[x]==inf)?-1:ans[x]);
    }

    return 0;
}
/*
5 6 1 5
1 3 4
1 2 1
2 3 1
2 4 1
3 5 1
4 3 1
*/

posted @   liweihang  阅读(346)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『Wannafly挑战赛2D Delete 删点最短路(拓扑序+最短路+线段树)』
点击右上角即可分享
微信分享提示