ahoi2005 lane 航线规划 (60分)——桥的运用

3 篇文章 0 订阅
1 篇文章 0 订阅

水60分

需要用到

一个叫桥的东西

这个桥是什么呢?

就是一条很重要的边,你把这条边去掉之后整个图就不连通了

接下来就可以发现,一张图的桥将这张图分成了一棵树

这棵树上的节点对应的是一个一个连通块

每一个连通块内的点到另一个连通块内的点之间的关键路径的条数

即为两个点之间桥的个数,也即为两个连通块在树上的路径

那么我们可以将原问题转化成求用桥构成的树上两点之间的距离了

那么

怎么求桥呢?怎么将原图用桥分开呢?

我们对原图进行一次dfs,在这过程中记录两个东西

dfn[i]:表示i的dfs序,即在dfs过程中被遍历到的顺序

low[i]:表示i能够连接到的最小的祖先,即i能够到达的已经被dfs过的dfs序最小的点

桥的判定:

如果对于一条边(u,v)

low[u]<dfn[v] 的话,那么这条边就为图上的一座桥

有了这个性质可以在dfs过程中求出桥了

求出桥之后,再考虑构建树边

如果把所有的桥全部拿走的话

可以看见整个图被分成了互不相连的好几个连通块

可以把这些连通块缩成树上的一个点

然后再把桥边放回去,构成树边

建完树之后就可以利用树上lca的知识来求树上两点之间的距离了

    #include<cstdio>  
    #include<iostream>  
    #include<algorithm>  
    #include<vector>  
    #include<cstring>  
    #include<cctype>  
    using namespace std;  
    const int MAXN=3e4+2,MAXE=1e5+2,S=20;  
    inline void Rd(int &res){  
        char c;res=0;  
        while(c=getchar(),!isdigit(c));  
        do res=(res<<3)+(res<<1)+(c^48);  
        while(c=getchar(),isdigit(c));  
    }  
    struct Edge{  
        int to,nxt;  
    }edge[MAXE];  
    int n,m,Q;  
    int head[MAXN],tot;  
    int e[MAXN][2];  
    int belongto[MAXN];  
    int isbridge[MAXN];  
    int dfn[MAXN],low[MAXN],T,bcnt;  
    vector<int>tree[MAXN];  
    int fa[MAXN][S],dep[MAXN];  
    inline void add(int a,int b){  
        edge[tot].to=b;edge[tot].nxt=head[a];head[a]=tot++;  
    }  
    void dfs(int x,int f){  
        dfn[x]=low[x]=++T;  
        for(int i=head[x];~i;i=edge[i].nxt){  
            int y=edge[i].to;  
            if(y==f)continue;  
            if(dfn[y]==0){  
                dfs(y,x);  
                if(low[y]>dfn[x])isbridge[i]=1,isbridge[i^1]=1;  
                else low[x]=min(low[x],low[y]);  
            }else low[x]=min(low[x],dfn[y]);  
        }  
    }  
    void setID(int x){  
        belongto[x]=bcnt;  
        for(int i=head[x];~i;i=edge[i].nxt){  
            if(isbridge[i]||belongto[edge[i].to])continue;  
            setID(edge[i].to);  
        }  
    }  
    void Tdfs(int now,int pre,int Dep){  
        fa[now][0]=pre;dep[now]=Dep;  
        for(int i=0;i<tree[now].size();i++){  
            int nxt=tree[now][i];  
            if(nxt==pre)continue;  
            Tdfs(nxt,now,Dep+1);  
        }  
    }  
    inline void init(){  
        for(int j=1;(1<<j)<n;j++)  
            for(int i=1;i<=n;i++)  
                fa[i][j]=fa[fa[i][j-1]][j-1];  
    }  
    inline void up(int &a,int step){  
        for(int i=0;i<S;i++)  
            if(step&(1<<i))  
                a=fa[a][i];  
    }  
    int LCA(int a,int b){  
        if(dep[a]>dep[b])swap(a,b);  
        up(b,dep[b]-dep[a]);  
        if(a!=b){  
            for(int i=S-1;i>=0;i--)  
                if(fa[a][i]!=fa[b][i])  
                    a=fa[a][i],b=fa[b][i];  
            a=fa[a][0];  
        }return a;  
    }  
    int main(){  
        memset(head,-1,sizeof(head));tot=0;  
        Rd(n),Rd(m),Rd(Q);  
        int a,b,type;  
        for(int i=0;i<m;i++){  
            Rd(a),Rd(b);  
            add(a,b);add(b,a);  
            e[i][0]=a;e[i][1]=b;  
        }  
        dfs(1,0);  
        for(int i=1;i<=n;i++)  
            if(!belongto[i]){  
                bcnt++;  
                setID(i);  
            }  
        for(int i=0;i<m;i++){  
            int a=belongto[e[i][0]],b=belongto[e[i][1]];  
            if(a==b)continue;  
            tree[a].push_back(b);  
            tree[b].push_back(a);  
        }  
        Tdfs(1,0,1);  
        init();  
        while(Q--){  
            Rd(type),Rd(a),Rd(b);  
            a=belongto[a];b=belongto[b];  
            int lca=LCA(a,b);  
            printf("%d\n",dep[a]+dep[b]-2*dep[lca]);  
        }  
        return 0;  
    }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值