zoukankan      html  css  js  c++  java
  • poj3694 边-双连通分量+lca

    题意:先给了一张无向图,然后依次加边,每次求桥的数量

    题解:先用一次tarjan,我们可以标记桥的位置和记录桥的数量同时记录fa数组,然后更新边的时候我们可以用lca,因为在tarjan缩点之后得到了一颗树,当连接a,b节点时,可以直观的看出从a,b的最近公共祖先到a,b之间所有的桥都会消失,我们可以不断更新桥的标记来输出答案,同时之前连的边对后面的(除了桥数以外)结果没有影响

    #include<map>
    #include<set>
    #include<list>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define C 0.5772156649
    #define pi acos(-1.0)
    #define ll long long
    #define mod 1000000007
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    
    using namespace std;
    using namespace __gnu_cxx;
    
    const double g=10.0,eps=1e-7;
    const int N=100000+10,maxn=100000+10,inf=0x3f3f3f;
    
    struct edge{
        int to,Next;
    }e[N*6];
    int head[N],cnt,fa[N];
    int dfn[N],low[N];
    int index,num,iscut[N];
    void add(int u,int v)
    {
        e[cnt].to=v;
        e[cnt].Next=head[u];
        head[u]=cnt++;
        e[cnt].to=u;
        e[cnt].Next=head[v];
        head[v]=cnt++;
    }
    void init(int n)
    {
        for(int i=1;i<=n;i++)
        {
            dfn[i]=low[i]=iscut[i]=0;
        }
        memset(head,-1,sizeof head);
        index=num=cnt=0;
    }
    void tarjan(int u,int f)
    {
        dfn[u]=low[u]=++index;
        int k=0;
        for(int i=head[u];~i;i=e[i].Next)
        {
            int x=e[i].to;
            if(x==f&&!k)
            {
                k++;
                continue;
            }
            if(!dfn[x])
            {
                fa[x]=u;
                tarjan(x,u);
                low[u]=min(low[u],low[x]);
                if(low[x]>dfn[u])num++,iscut[x]=1;
            }
            else low[u]=min(low[u],dfn[x]);
        }
    }
    void lca(int a,int b)
    {
        if(dfn[a]>dfn[b])swap(a,b);
        while(dfn[a]>dfn[b])
        {
            if(iscut[a])num--;
            iscut[a]=0;
            a=fa[a];
        }
        while(a!=b)
        {
            if(iscut[a])num--;
            if(iscut[b])num--;
            iscut[a]=iscut[b]=0;
            a=fa[a];b=fa[b];
        }
    }
    int main()
    {
        int n,m,res=1;
        while(~scanf("%d%d",&n,&m))
        {
            if(!n&&!m)break;
            init(n);
            for(int i=0;i<m;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                add(a,b);
            }
            fa[1]=1;
            tarjan(1,-1);
            printf("Case %d:
    ",res++);
            int q;
            scanf("%d",&q);
            while(q--)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                lca(a,b);
                printf("%d
    ",num);
            }
            puts("");
        }
        return 0;
    }
    /************
    
    ************/
    View Code
  • 相关阅读:
    c#修改config中的AppSettings属性
    C​#​小​实​例​之​-​-​-​C​#​判​断​网​络
    走过2013,走进2014
    前端工程师常去的网站
    正则表达式中文匹配
    浅谈 -webkit-tap-highlight-color 属性
    JS前端开发判断是否是手机端并跳转操作(小结)(转)
    swf文件加密基础(转)
    Object与Dictionary的区别
    关于事件机制的理解
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/7745826.html
Copyright © 2011-2022 走看看