zoukankan      html  css  js  c++  java
  • BZOJ 2725: [Violet 6]故乡的梦

    题意:给出一个无向图,给定起点和终点。给出q个询问,每个询问是删除某条边之后,起点到终点的最短路变成什么?询问之间是独立的。

    这道题不错,但是蒟蒻完全不会做qaq,解法参考Claris大佬的。

    首先容易想到如果删掉的边不在最短路上的话,最短路是不会变的。于是我们先跑一遍最短路,找出一条最短路。

    终点是如果删掉最短路上的边怎么办?

    这里我们反过来考虑,我们考虑,每一条非最短路边对最短路的贡献。首先分别以S和T为起点做一遍最短路记为d1[i]和d2[i],同时随便抓一条最短路Path并把它编号。

    在以S为起点的最短路图,这必定是一个DAG,我们计算f1[i]代表(最早的)(在最短路Path上的)(能到达i点)的点是谁?

    同理以T为起点的最短路图,我们计算f2[i]代表(最晚的)(在最短路Path上的)(能到达i点)的点是谁?

    以上两个信息可以用拓扑排序DP计算得到。

    那么对于每一条非最短路Path的边(x,y),它的贡献是什么:对于当区间 [ f1[x],f2[y] ]的边被删除时,边(x,y)能提供一条长度为d1[x]+len(x,y)+d2[y]的最短路,这里要注意所谓贡献,并不是只要删掉区间

    [ f1[x],f2[y] ]的边,d1[x]+len(x,y)+d2[y] 就是答案,贡献的意思是这可以作为一种选择,并且这个选择是所有基于边(x,y)中最好的,因为d1[x]是正向最短路,d2[y]是反向最短路。

    由上面这段路就得出做法了,我们用线段树维护这些所有选择,并选择最短的,这就是答案。

    细节看代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,LL> pii;
    const LL N=4e5+10;
    const LL INF=0x3f3f3f3f3f3f3f3f;
    LL n,m,s,t,T,x[N],y[N],z[N],id[N],deg[N];
    vector<LL> G[N];
    LL tot,d1[N],d2[N],pre[N],path[N],f1[N],f2[N];
    
    LL cnt=1,head[N],to[N<<1],nxt[N<<1],len[N<<1];
    void add_edge(LL x,LL y,LL z) {
        nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
    }
    
    bool vis[N]; 
    priority_queue<pii> q;
    void Dijkstra(LL d[],LL s) {
        while (!q.empty()) q.pop();
        memset(vis,0,sizeof(vis));
        d[s]=0; q.push(make_pair(0,s));
        while (!q.empty()) {
            pii x=q.top(); q.pop();
            if (vis[x.second]) continue;
            vis[x.second]=1;
            for (LL i=head[x.second];i;i=nxt[i]) {
                LL y=to[i];
                if (d[y]>d[x.second]+len[i]) {
                    d[y]=d[x.second]+len[i];
                    q.push(make_pair(-d[y],y));
                }
            }
        }
    }
    
    queue<LL> Q;
    void toposort(LL f[],LL now) {
        while (!Q.empty()) Q.pop();
        Q.push(now);
        while (!Q.empty()) {
            LL x=Q.front(); Q.pop();
            if (id[x]) f[x]=id[x];
            for (LL i=0;i<G[x].size();i++) {
                LL y=G[x][i];
                if (now==s) f[y]=min(f[y],f[x]);
                if (now==t) f[y]=max(f[y],f[x]);
                if (--deg[y]==0) Q.push(y);
            }
        }
    }
    
    LL Min[N<<2],tag[N<<2];
    void build(LL rt,LL l,LL r) {
        Min[rt]=tag[rt]=INF;
        if (l==r) return;
        LL mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    }
    
    void pushdown(LL rt) {
        Min[rt<<1]=min(Min[rt<<1],tag[rt]); Min[rt<<1|1]=min(Min[rt<<1|1],tag[rt]);
        tag[rt<<1]=min(tag[rt<<1],tag[rt]); tag[rt<<1|1]=min(tag[rt<<1|1],tag[rt]);
        tag[rt]=INF;
    }
    
    void update(LL rt,LL l,LL r,LL ql,LL qr,LL v) {
        if (ql<=l && r<=qr) { Min[rt]=min(Min[rt],v),tag[rt]=min(tag[rt],v); return; }
        LL mid=l+r>>1;
        pushdown(rt);
        if (ql<=mid) update(rt<<1,l,mid,ql,qr,v);
        if (qr>mid) update(rt<<1|1,mid+1,r,ql,qr,v);
        Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
    }
    
    LL query(LL rt,LL l,LL r,LL ql,LL qr) {
        if (ql<=l && r<=qr) return Min[rt];
        LL mid=l+r>>1,ret=INF;
        pushdown(rt);
        if (ql<=mid) ret=min(ret,query(rt<<1,l,mid,ql,qr));
        if (qr>mid) ret=min(ret,query(rt<<1|1,mid+1,r,ql,qr));
        return ret;
    }
    
    bool onpath(LL x,LL y) {
        if (!id[x] || !id[y]) return 0;
        if (id[x]+1==id[y] || id[y]+1==id[x]) return 1;
        return 0;
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out2.txt","w",stdout);
        cin>>n>>m;
        for (LL i=1;i<=m;i++) {
            scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);
            add_edge(x[i],y[i],z[i]); add_edge(y[i],x[i],z[i]);
        }
        cin>>s>>t; cin>>T;
        if (s==t) { for (LL i=1;i<=T;i++) puts("0"); return 0; }
        memset(d1,0x3f,sizeof(d1));
        Dijkstra(d1,s);
        if (d1[t]>=INF) { for (LL i=1;i<=T;i++) puts("Infinity"); return 0; }
        memset(d2,0x3f,sizeof(d2));
        Dijkstra(d2,t);
        
        memset(deg,0,sizeof(deg));
        for (LL i=1;i<=m;i++) {
            if (d1[x[i]]+z[i]==d1[y[i]]) G[x[i]].push_back(y[i]),deg[y[i]]++,pre[y[i]]=x[i];
            if (d1[y[i]]+z[i]==d1[x[i]]) G[y[i]].push_back(x[i]),deg[x[i]]++,pre[x[i]]=y[i];
        } 
        for (LL i=t;i;i=pre[i]) path[++tot]=i,id[i]=tot;
        for (LL i=1;i<=n;i++) if (id[i]) id[i]=tot-id[i]+1;
        memset(f1,0x3f,sizeof(f1));
        toposort(f1,s);
        
        memset(deg,0,sizeof(deg));
        for (LL i=1;i<=n;i++) G[i].clear();
        for (LL i=1;i<=m;i++) {
            if (d2[x[i]]+z[i]==d2[y[i]]) G[x[i]].push_back(y[i]),deg[y[i]]++;
            if (d2[y[i]]+z[i]==d2[x[i]]) G[y[i]].push_back(x[i]),deg[x[i]]++;
        }
        memset(f2,0,sizeof(f2));
        toposort(f2,t);
        
        tot--; build(1,1,tot);
        for (LL i=1;i<=m;i++) 
            if (!onpath(x[i],y[i])) {
                LL t1=f1[x[i]],t2=f2[y[i]]; t2--;
                if (t1<INF&&t2>0&&t1<=t2) update(1,1,tot,t1,t2,d1[x[i]]+d2[y[i]]+z[i]);
                t1=f1[y[i]],t2=f2[x[i]]; t2--;
                if (t1<INF&&t2>0&&t1<=t2) update(1,1,tot,t1,t2,d1[y[i]]+d2[x[i]]+z[i]);
            }    
        
        while (T--) {
            LL x,y; scanf("%lld%lld",&x,&y);
            if (!onpath(x,y)) printf("%lld
    ",d1[t]);
            else {
                x=id[x]; y=id[y]; if (x>y) swap(x,y); y--;
                LL ans=query(1,1,tot,x,y);
                if (ans>=INF) puts("Infinity"); else printf("%lld
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    深度学习GPU集群管理软件 OpenPAI 简介
    图片加数字盲水印
    Kubernetes核心概念简介
    一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)
    【OfficeWebViewer】在线预览Word,Excel~
    【Java】大文本字符串滤重的简单方案
    Java应用集群下的定时任务处理方案(mysql)
    《将博客搬至CSDN》
    [转]Fiddler抓取Android真机上的HTTPS包
    [Java Collection]List分组之简单应用.
  • 原文地址:https://www.cnblogs.com/clno1/p/10820268.html
Copyright © 2011-2022 走看看