[bzoj2725]故乡的梦——最短路+线段树

题目大意:

给定一个带权无向图,每次询问删除一条边之后从S到T的最短路是多少?(各个询问之间独立)

思路:

如果删除的边不在最短路中或者可以被替换,那么答案即为最短路。
如果删除的边在最短路中并且不可以被替换,考虑将这条边删除的新图:
假设原来的最短路为\(S->T\),那么新的最短路一定是\(S->u->x->y->v->T\)(其中u,v在原来的最短路上,x,y不在原来的最短路上)
于是我们发现如果删除了这条边之后S和T联通,那么一定会经过形如\(x->y\)这样的路径,即经过原本不在最短路中的边。
并且对于\(x->y\)中的一条边(uu,vv),\(S->uu\)\(vv->T\)一定是两条最短的路径于是我们枚举出每一条不在最短路中的边(uu,vv),并计算出对应的最早的u和最晚的v,用强制经过(uu,vv)的最短路去更新u和v中间缺失的那些边的答案。为了方便,在具体实现的时候随意提出一条\(S->T\)的最短路并把它当作唯一的最短路即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<endl
#define pii pair<ll,int>
#define fi first
#define se second
#define mk make_pair
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj2725.in","r",stdin);
    freopen("bzoj2725.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=2e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,q,ss,tt;
int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1;
ll w[maxn<<1],dis[maxn],ddis[maxn];
int pre[maxn],nex[maxn],pre_node[maxn],ls[maxn],cnt_ls,num[maxn],cnt_num;
int ps[maxn],pt[maxn];
map<int,int>mp[maxn];

void add(int u,int v,ll val){
    las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;
    las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; w[cnte]=val;
}

void Dijkstra_pre(){
    priority_queue<pii,vector<pii>,greater<pii> >qu;
    memset(dis,63,sizeof(dis));
    dis[ss]=0; qu.push(mk(0,ss));
    while(!qu.empty()){
        int u=qu.top().se; ll d=qu.top().fi;
        qu.pop();
        if(dis[u]!=d)continue;
        for(int i=beg[u];i;i=las[i]){
            int v=to[i];
            if(d+w[i]<dis[v]){
                pre[v]=i/2;
                pre_node[v]=u;
                dis[v]=d+w[i];
                qu.push(mk(dis[v],v));
            }
        }
    }

    int p=tt;
    while(pre_node[p]){
        num[pre[p]]=++cnt_num;
        nex[pre_node[p]]=pre[p];
        ls[++cnt_ls]=p;
        p=pre_node[p];
    }
    ls[++cnt_ls]=ss;
    REP(i,1,cnte/2)if(num[i])
        num[i]=cnt_num-num[i]+1;
}

void Dijkstra1(){
    priority_queue<pii,vector<pii>,greater<pii> >qu;
    memset(ddis,63,sizeof(ddis));
    REP(i,1,cnt_ls){
        ddis[ls[i]]=dis[ls[i]];
        qu.push(mk(ddis[ls[i]],ls[i]));
        ps[ls[i]]=ls[i];
    }
    while(!qu.empty()){
        int u=qu.top().se; ll d=qu.top().fi;
        qu.pop();
        if(ddis[u]!=d)continue;
        for(int i=beg[u];i;i=las[i]){
            int v=to[i];
            if(d+w[i]<ddis[v]){
                ps[v]=ps[u];
                ddis[v]=d+w[i];
                qu.push(mk(ddis[v],v));
            }
            else if(d+w[i]==ddis[v] && ps[v]!=v && ps[u]<ps[v])
                ps[v]=ps[u];
        }
    }
}

void Dijkstra2(){
    priority_queue<pii,vector<pii>,greater<pii> >qu;
    memset(ddis,63,sizeof(ddis));
    REP(i,1,cnt_ls){
        ddis[ls[i]]=dis[tt]-dis[ls[i]];
        qu.push(mk(ddis[ls[i]],ls[i]));
        pt[ls[i]]=ls[i];
    }
    while(!qu.empty()){
        int u=qu.top().se; ll d=qu.top().fi;
        qu.pop();
        if(ddis[u]!=d)continue;
        for(int i=beg[u];i;i=las[i]){
            int v=to[i];
            if(d+w[i]<ddis[v]){
                pt[v]=pt[u];
                ddis[v]=d+w[i];
                qu.push(mk(ddis[v],v));
            }
            else if(d+w[i]==ddis[v] && pt[v]!=v && pt[u]<pt[v])
                pt[v]=pt[u];
        }
    }
}

void init(){
    read(n); read(m);
    int u,v; ll val;
    REP(i,1,m){
        read(u),read(v),read(val);
        add(u,v,val); mp[u][v]=mp[v][u]=cnte/2;
    }
    read(ss); read(tt);
    Dijkstra_pre();
    Dijkstra1();
    Dijkstra2();
}

struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
    ll Min[maxn<<2];
    void update(int rt,int l,int r,int L,int R,ll x){
        if(L>R || !L || !R)return;
        if(L<=l && r<=R)Min[rt]=min(Min[rt],x);
        else{
            if(L<=mid)update(lson,L,R,x);
            if(R>=mid+1)update(rson,L,R,x);
        }
    }
    ll query(int rt,int l,int r,int p){
        if(l==r)return Min[rt];
        if(p<=mid)return min(Min[rt],query(lson,p));
        return min(Min[rt],query(rson,p));
    }
}T;

void work(){
    memset(T.Min,63,sizeof(T.Min));
    for(int i=2;i<=cnte;i+=2)if(!num[i/2]){
        int u=to[i],v=to[i^1];
        T.update(1,1,cnt_num,num[nex[ps[u]]],num[pre[pt[v]]],dis[u]+ddis[v]+w[i]);
        T.update(1,1,cnt_num,num[nex[ps[v]]],num[pre[pt[u]]],dis[v]+ddis[u]+w[i]);
    }
    read(q);
    int u,v;
    REP(i,1,q){
        read(u),read(v);
        int id=mp[u][v];
        if(!num[id])printf("%lld\n",dis[tt]);
        else{
            ll ans=T.query(1,1,cnt_num,num[id]);
            if(ans==inf)puts("Infinity");
            else printf("%lld\n",ans);
        }
    }
}

int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ylsoi/p/9861086.html