• BZOJ2125 最短路


    每个点有两个值,一个是从根到这个点的最短路d[i],一个是从根沿dfs树到这个点的距离rd[i].

    之后是一个很牛逼的建图,把环上的点都连到环中深度最浅的点得到一颗树,并维护每个点所在的环以及每个环的环长。

    对于一个询问(x,y),假设dep[x]>dep[y],分情况:

    1.如果x和y的lca是y,那么答案为d[x]-d[y].

    2.如果x和y的lca没在环里,那么答案为d[x]+d[y]-2*d[lca].

    3.如果x和y的lca在环里,设x,y向上走遇到的第一个环上节点分别是a,b,那么答案为d[x]-d[a]+d[y]-d[b]+min(abs(rd[a]-rd[b]),环长-abs(rd[a]-rd[b])).

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N=10005,M=100005;
    int n,m,q,e=1,x,y,z,ti,cn,hd[N],nx[M],to[M],w[M],dl[M],dfn[N],st[N],d[N],v[N],rd[N],dp[N],bl[N],ln[N],f[N][14];
    void ad(int x,int y,int z) {to[++e]=y,w[e]=z,nx[e]=hd[x],hd[x]=e;}
    
    void spfa() {
        memset(d,0x3f,sizeof d);
        queue<int> q; q.push(1),d[1]=0;
        while(!q.empty()) {
            int u=q.front(); q.pop();
            v[u]=0;
            for(int i=hd[u];i;i=nx[i]) if(d[to[i]]>d[u]+w[i]) {
                d[to[i]]=d[u]+w[i];
                if(!v[to[i]]) v[to[i]]=1,q.push(to[i]);
            }
        }
    }
    void gt(int x,int y) {
        if(x==y) return;
        bl[x]=cn,ad(y,x,0),dl[st[x]]=dl[st[x]^1]=1,ln[cn]+=w[st[x]],gt(to[st[x]^1],y); 
    }
    void dfs(int x) {
        dfn[x]=++ti;
        for(int i=hd[x];i;i=nx[i]) if(i!=(st[x]^1)&&i<=m*2+1) {
            if(!dfn[to[i]]) rd[to[i]]=rd[x]+w[i],st[to[i]]=i,dfs(to[i]);
            else if(dfn[to[i]]<dfn[x]) ln[++cn]=w[i],gt(x,to[i]);
        }
    }
    void dfs2(int x) {
        for(int i=hd[x];i;i=nx[i]) if(!dl[i]&&!dp[to[i]]) f[to[i]][0]=x,dp[to[i]]=dp[x]+1,dfs2(to[i]);
    }
    
    int qry(int x,int y) {
        if(dp[x]<dp[y]) swap(x,y);
        int a=x,b=y;
        for(int i=13;~i;i--) if(dp[f[x][i]]>=dp[y]) x=f[x][i];
        if(x==y) return d[a]-d[b];
        for(int i=13;~i;i--) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
        if(bl[x]&&bl[x]==bl[y]) {
            int r=abs(rd[x]-rd[y]);
            return d[a]-d[x]+d[b]-d[y]+min(r,ln[bl[x]]-r);
        }
        return d[a]+d[b]-2*d[f[x][0]];
    }
    
    int main() {
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),ad(x,y,z),ad(y,x,z);
        spfa(),dfs(1),dp[1]=1,dfs2(1);
        for(int j=1;j<14;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
        while(q--) scanf("%d%d",&x,&y),printf("%d
    ",qry(x,y));
        return 0;
    }
  • 相关阅读:
    代码控制数据流量开关
    用wifi来调试应用程序
    详细解读LruCache类
    修改博客园默认的代码字体大小
    通过Gson解析Json数据
    Docker、Kubernetes的 CICD实现思路
    React中路由传参及接收参数的方式
    微信小程序开发工具调试没问题,真机调试Provisional headers are shown
    物联网卡三码
    【微信开发】-- 企业转账到用户
  • 原文地址:https://www.cnblogs.com/juruolty/p/6438695.html
Copyright © 2020-2023  润新知