ahoi2005 lane 航線規劃 (60分)——橋的運用

水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;  
    }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章