• Codeforces 231E


    231E - Cactus

    给一个10^5个点的无向图,每个点最多属于一个环,规定两点之间的简单路:从起点到终点,经过的边不重复

    给10^5个询问,每个询问两个点,问这两个点之间有多少条简单路。

    挺综合的一道题目,无向图连通分量,缩点,LCA 都考察到了。。

    因为每个点最多属于一个环,因此把所有环缩点,就可以得到一棵树

    然后对于每个询问,用LCA查找从起点到终点有多少个环

    并查集处理的时候挂了一发,注意LCA时合并两个并查集,根节点深度小的作为父亲。。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<string>
    #include<sstream>
    #define eps 1e-9
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define MAXN 100005
    #define MAXM 400005
    #define INF 0x3fffffff
    #define PB push_back
    #define MP make_pair
    #define X first
    #define Y second
    #define clr(x,y) memset(x,y,sizeof(x));
    using namespace std;
    typedef long long LL;
    int i,j,k,n,m,x,y,T,big,cas,len;
    bool flag;
    
    int edge,head[MAXN],bin[MAXN],headS[MAXN],edgeS,vis[MAXN],d[MAXN],id[MAXN],num[MAXN];
    struct edgenode
    {
        int to,next,flag;
    } G[MAXM],S[MAXM];
    
    void add_edge(int x,int y)
    {
        G[edge].to=y;
        G[edge].flag=0;
        G[edge].next=head[x];
        head[x]=edge++;
    }
    
    void add_edgeS(int x,int y)
    {
        S[edgeS].to=y;
        S[edgeS].flag=0;
        S[edgeS].next=headS[x];
        headS[x]=edgeS++;
    }
    
    int fa[MAXN];
    int findset(int x)
    {
        return x==fa[x]?x:fa[x]=findset(fa[x]);
    }
    void unionset(int x,int y)
    {
        fa[findset(x)]=findset(y);
    }
    
    int dfn[MAXN],low[MAXN],time;
    void dfs(int u,int fa)
    {
        vis[u]=1;
        dfn[u]=low[u]=++time;
        for (int i=head[u];i!=-1;i=G[i].next)
        {
            int v=G[i].to;
            if (v!=fa && vis[v]==1)
            {
                low[u]=min(low[u],dfn[v]);
            }
    
            if (!vis[v])
            {
                dfs(v,u);
                low[u]=min(low[u],low[v]);
                if (low[v]>dfn[u]) G[i].flag=1;
            }
        }
        vis[u]=2;
    }
    
    void dive(int u,int scc)
    {
        id[u]=scc;
        vis[u]=1;
        num[scc]++;
        for (int i=head[u];i!=-1;i=G[i].next)
        {
            if (!G[i].flag && !vis[G[i].to])
                dive(G[i].to,scc);
        }
    }
    
    void dis(int u,int dep)//记录当前节点到根节点有多少个“环”
    {
        vis[u]=1;
        d[u]=dep;
        for (int i=headS[u];i!=-1;i=S[i].next)
        {
            int v=S[i].to;
            if (!vis[v])
            {
                if (num[v]>2) dis(v,dep+1);
                else dis(v,dep);
            }
        }
    }
    
    vector<pair<int,int> > Q[MAXN];
    int ans[MAXN];
    void tarjan(int u)
    {
        vis[u]=true;
        for (int i=0;i<Q[u].size();i++)
        {
            int v=Q[u][i].X,id=Q[u][i].Y;
            if (vis[v])
            {
                int com=findset(v);
                ans[id]=d[u]+d[v]-2*d[com];
                if (num[com]>2) ans[id]++;
            }
        }
    
        for (int i=headS[u];i!=-1;i=S[i].next)
        {
            int v=S[i].to;
            if (!vis[v])
            {
                tarjan(v);
                unionset(v,u);
            }
        }
    }
    
    
    int main()
    {
        memset(head,-1,sizeof(head));
        edge=0;
        memset(headS,-1,sizeof(headS));
        edgeS=0;
        scanf("%d%d",&n,&m);
        while (m--)
        {
            scanf("%d%d",&x,&y);
            add_edge(x,y);
            add_edge(y,x);
        }
    
        dfs(1,-1); 
    
        memset(vis,0,sizeof(vis));
        int scc=1;
        for (int i=1;i<=n;i++)
        {
            if (!vis[i]) dive(i,scc++);
        }
    
        for (i=1;i<=n;i++)
        {
            for (int j=head[i];j!=-1;j=G[j].next)
            {
                int v=G[j].to;
                if (id[i]!=id[v])
                {
                    add_edgeS(id[i],id[v]);
                    add_edgeS(id[v],id[i]);
                }
            }
        }
    
        int q;
        scanf("%d",&q);
        for (i=0;i<q;i++)
        {
            scanf("%d%d",&x,&y);
            x=id[x];y=id[y];
            Q[x].PB(MP(y,i));
            Q[y].PB(MP(x,i));
        }
    
        memset(vis,0,sizeof(vis));
        if (num[1]>2) dis(1,1); else dis(1,0);
    
        memset(vis,0,sizeof(vis));
        for (i=1;i<=n;i++) fa[i]=i;
        tarjan(1);
    
        bin[0]=1;
        for(int i=1;i<MAXN;i++)
            bin[i]=bin[i-1]*2%1000000007;
        for (int i=0;i<q;i++)
        {
            printf("%d
    ",bin[ans[i]]);
        }
        return 0;
    }
  • 相关阅读:
    jsADS的库(待更新)
    javascript设计模式工厂方法模式
    jQuery星级评价
    邮政编码联动地址
    ADS图像缩放与剪裁(只是完成了前台的功能,传送数据到后台的功能待完成)
    ie6png透明解决(ietester的ie6有问题,原生ie6是没问题的)
    javascript设计模式桥接模式
    每一个人都应该学会执着
    防止电脑被攻击
    获取用户的IP地址的三个属性的区别
  • 原文地址:https://www.cnblogs.com/zhyfzy/p/4696208.html
Copyright © 2020-2023  润新知