• 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
  • 相关阅读:
    题目1007:奥运排序问题(自定义排序问题)
    题目1005:Graduate Admission(录取算法)
    九度OJ小结2
    题目1049:字符串去特定字符(简单字符判断)
    题目1111:单词替换(字符串查找)
    题目1168:字符串的查找删除(字符串操作)
    题目1455:珍惜现在,感恩生活(多重背包问题)
    题目1454:Piggy-Bank(完全背包问题)
    题目1453:Greedy Tino(dp题目)
    题目1452:搬寝室(dp题目)
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/7745826.html
Copyright © 2020-2023  润新知