• [边双连通分量][LCA] Codeforces 231E


    题目大意

    给一个 (n)个点,(m) 条边的点仙人掌(点仙人掌定义:在简单连通图中,每个点最多属于一个简单环),(q) 次询问从 (x)(y) 有多少条简单路径,模1000000007。((n,mleq 10^5))

    题解

    考虑在一个环上,从 (u)(v) 有两条不同的简单路径。那么假设从 (u)(v) 经过了 (cnt) 个环,那么简单路径数目即为 (2^{cnt})。因为环是一个边双连通分量,我们可以使用Tarjan算法对边双连通分量进行缩点,形成一棵树,对于多个点缩成一个点的点,我们把它标记成黑色,单点的标记成白色,那么我们可以求出 (u,v) 缩点后的LCA,从而知道 (u)(v) 的路径上有多少个黑色点,也就是有多少个环。

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <cstdio>
    #include <vector>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType &T){
        elemType X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        T=(w?-X:X);
    }
    
    struct Graph{
        struct edge{int Next,to;};
        edge G[200010];
        int head[100010];
        int cnt;
    
        Graph():cnt(2){}
        void clear(int node_num=0){
            cnt=2;
            if(node_num==0) memset(head,0,sizeof(head));
            else fill(head,head+node_num+5,0);
        }
        void add_edge(int u,int v){
            G[cnt].to=v;
            G[cnt].Next=head[u];
            head[u]=cnt++;
        }
    };
    Graph G,G2;
    int N,M,Q;
    
    int dfn[100010],low[100010],bcc[100010],stk[100010],bcc_size[100010];
    int index,bcc_id,top;
    
    void Tarjan(int u,int in_edge){
        dfn[u]=low[u]=++index;
        stk[++top]=u;
        for(int i=G.head[u];i;i=G.G[i].Next){
            int v=G.G[i].to;
            if(!dfn[v]){Tarjan(v,i);low[u]=min(low[u],low[v]);}
            else if(i!=(in_edge^1)) low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            ++bcc_id;int x;
            do{x=stk[top--];bcc[x]=bcc_id;++bcc_size[bcc_id];
            }while(x!=u);
        }
        return;
    }
    
    inline void build_new_graph(){
        for(RG u=1;u<=N;++u){
            for(int i=G.head[u];i;i=G.G[i].Next){
                int v=G.G[i].to;
                if(bcc[u]!=bcc[v]) G2.add_edge(bcc[u],bcc[v]);
            }
        }
    }
    
    int Deep[100010],Anc[100010][18],Count[100010];
    
    void DFS_Init(int u,int fa){
        if(bcc_size[u]!=1) Count[u]=1+Count[fa];
        else Count[u]=Count[fa];
        Anc[u][0]=fa;
        for(int i=1;i<18;++i)
            Anc[u][i]=Anc[Anc[u][i-1]][i-1];
        for(int i=G2.head[u];i;i=G2.G[i].Next){
            int v=G2.G[i].to;
            if(v==fa) continue;
            Deep[v]=Deep[u]+1;
            DFS_Init(v,u);
        }
        return;
    }
    
    int LCA(int u,int v){
        int Root=1;
        if(u==Root || v==Root) return Root;
        if(Deep[u]<Deep[v]) swap(u,v);
        for(RG i=17;i>=0;--i){
            if(Deep[Anc[u][i]]>=Deep[v])
                u=Anc[u][i];
        }
        if(u==v) return u;
        for(RG i=17;i>=0;--i){
            if(Anc[u][i]!=Anc[v][i]){
                u=Anc[u][i];	
                v=Anc[v][i];
            }
        }
        return Anc[u][0];
    }
    
    const LL MOD=1000000007LL;
    
    LL ExPow(LL b,LL n){
        LL x=1;
        LL Power=b%MOD;
        while(n){
            if(n&1) x=x*Power%MOD;
            Power=Power*Power%MOD;
            n>>=1;
        }
        return x;
    }
    
    int main(){
        Read(N);Read(M);
        for(RG i=1;i<=M;++i){
            int u,v;
            Read(u);Read(v);
            G.add_edge(u,v);
            G.add_edge(v,u);
        }
        for(int i=1;i<=N;++i)
            if(!dfn[i]) Tarjan(i,0);
        build_new_graph();
        DFS_Init(1,0);
        Read(Q);
        while(Q--){
            int u,v;
            Read(u);Read(v);
            u=bcc[u];v=bcc[v];
            int c=LCA(u,v);
            LL Ans=0;
            if(bcc_size[c]==1) Ans=ExPow(2,Count[u]+Count[v]-Count[c]*2);
            else Ans=ExPow(2,Count[u]+Count[v]-Count[c]*2+1);
            printf("%lld
    ",Ans);
        }
        return 0;
    }
    
  • 相关阅读:
    省选D2T2 滚榜
    CF1516E(第一类斯特林数)
    Atcoder ZEP F题
    Atcoder ARC 115 A~D
    Atcoder ARC 117
    「舞蹈链 DLX 」学习笔记
    「FJOI-2021」仰视那片离我远去了的天空。
    「UVA1603」破坏正方形 Square Destroyer
    「网络流」学习笔记
    博客搬家
  • 原文地址:https://www.cnblogs.com/AEMShana/p/13559477.html
Copyright © 2020-2023  润新知