BZOJ 2725 [Violet 6]故乡的梦 最短路

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 200005
#define INF (1ll<<60)
using namespace std;
typedef long long LL;
namespace Segment_Tree {
    struct Node {
        Node* ch[2];
        int l,r;
        LL v;
        Node() {}
        Node(int _l,int _r):l(_l),r(_r),v(INF) {
            ch[0]=ch[1]=NULL;
        }
        void* operator new(size_t) {
            static Node *mempool,*C;
            if(mempool==C) mempool=(C=new Node[1<<20])+(1<<20);
            return C++;
        }
    }*root;
    void Init(Node*& o,int l,int r) {
        o=new Node(l,r);
        if(l==r) return ;
        int mid=l+r>>1;
        Init(o->ch[0],l,mid), Init(o->ch[1],mid+1,r);
        return ;
    }
    void Change(Node* o,int l,int r,LL v) {
        if(o->l==l && o->r==r) {
            o->v=min(o->v,v);
            return ;
        }
        int mid=o->l+o->r>>1;
        if(r<=mid) Change(o->ch[0],l,r,v);
        else if(l>mid) Change(o->ch[1],l,r,v);
        else Change(o->ch[0],l,mid,v), Change(o->ch[1],mid+1,r,v);
        return ;
    }
    LL Query(Node* o,int pos) {
        if(o->l==o->r) return o->v;
        int mid=o->l+o->r>>1,dir=pos<=mid?0:1;
        return min(Query(o->ch[dir],pos),o->v);
    }
}
#define ST Segment_Tree
struct Data {
    int ord;
    LL val;
    Data() {}
    Data(int _ord,LL _val):ord(_ord),val(_val) {}
    bool operator < (const Data& rhs) const {
        return val>rhs.val;
    }
};
struct Edge {
    int from,to,nxt,val;
    Edge() {}
    Edge(int _from,int _to,int _nxt,int _val):
        from(_from),to(_to),nxt(_nxt),val(_val) {}
}e[N*2];
int n,m,tot,S,T,Q,top,fir[N],fromS[N],fromT[N],seq[N],pos[N];
LL distS[N],distT[N],ans[N];
void Add_Edge(int u,int v,int c) {
    e[++tot]=Edge(u,v,fir[u],c), fir[u]=tot;
    e[++tot]=Edge(v,u,fir[v],c), fir[v]=tot;
    return ;
}
void Dijkstra(int st,LL dist[]) {
    static bool k[N];
    priority_queue<Data> q;
    for(int i=1;i<=n;++i) dist[i]=INF, k[i]=false;
    dist[st]=0, q.push(Data(st,0));
    while(!q.empty()) {
        Data tmp=q.top(); q.pop();
        int x=tmp.ord;
        if(k[x]) continue;
        k[x]=true;
        for(int i=fir[x];~i;i=e[i].nxt) {
            if(dist[e[i].to]<=dist[x]+e[i].val) continue;
            dist[e[i].to]=dist[x]+e[i].val;
            q.push(Data(e[i].to,dist[e[i].to]));
        }
    }
    return ;
}
void Find_path() {
    int x=S;
    while(x!=T) {
        seq[++top]=x;
        pos[x]=top;
        for(int i=fir[x];~i;i=e[i].nxt) {
            if(distT[e[i].to]+e[i].val>distT[x]) continue;
            x=e[i].to;
            break;
        }
    }
    seq[++top]=x, pos[x]=top;
    return ;
}
void bfs(int ord,LL dist[],int from[]) {
    int st=seq[ord];
    queue<int> q;
    q.push(st);
    while(!q.empty()) {
        int x=q.front(); q.pop();
        for(int i=fir[x];~i;i=e[i].nxt)
            if(!from[e[i].to] && dist[e[i].to]==dist[x]+e[i].val)
                from[e[i].to]=ord, q.push(e[i].to);
    }
    return ;
}
void calc_from() {
    for(int i=1;i<=top;++i) fromS[seq[i]]=fromT[seq[i]]=i;
    for(int i=1;i<=top;++i) bfs(i,distS,fromS);
    for(int i=top;i;--i) bfs(i,distT,fromT);
    return ;
}
int main() {
    memset(fir,-1,sizeof fir), tot=-1;
    scanf("%d%d",&n,&m);
    for(int i=1,x,y,z;i<=m;++i)
        scanf("%d%d%d",&x,&y,&z), Add_Edge(x,y,z);
    scanf("%d%d",&S,&T);
    Dijkstra(S,distS), Dijkstra(T,distT);
    Find_path(), calc_from();
    ST::Init(ST::root,1,top-1);
    for(int i=0;i<=tot;++i) {
        int from=e[i].from,to=e[i].to;
        if(pos[from] && pos[to] && abs(pos[from]-pos[to])==1) continue;
        if(fromS[from] && fromT[to] && fromS[from]<fromT[to]) ST::Change(ST::root,fromS[from],fromT[to]-1,distS[from]+e[i].val+distT[to]);
    }
    for(int i=1;i<top;++i) ans[i]=ST::Query(ST::root,i);
    for(scanf("%d",&Q);Q;--Q) {
        int x,y;
        scanf("%d%d",&x,&y);
        if(pos[x]>pos[y]) swap(x,y);
        LL tmp;
        if(pos[x] && pos[y] && pos[x]+1==pos[y]) tmp=ans[pos[x]];
        else tmp=distS[T];
        printf(tmp==INF ? "Infinity\n" : "%lld\n",tmp);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值