zoukankan      html  css  js  c++  java
  • POJ3694 Network【连通分量+LCA】

    题意:

    一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上)。

    思路:

    首先运行一次Tarjan,求出桥和缩点,那么远无向图将缩点为一棵树,树边正好是原来的桥。每次连接两点,看看这两点是不是在同一个缩点内,如果是,那么缩点后的树没任何变化,如果两点属于不同的缩点,那么连接起来,然后找这两个缩点的LCA,因为从点u到LCA再到点v再到点u,将形成环,里面的树边都会变成不是桥。计数的时候注意,有些树边可能之前已经被标记了,这次再经过不能再标记。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    
    using namespace std;
    #define N 100010
    #define M 200010
    
    vector<int> ver[N];
    int head[N],dfn[N],low[N],vis[N],fa[N],dcnt,bcnt;
    
    struct edge{
        int u,v,used,next;
    }e[2*M];
    
    bool isbridge[N];
    
    inline void add(int u, int v ,int &k)
    {
        e[k].v = v; e[k].used = 0;
        e[k].next = head[u]; head[u] = k++;
    }
    
    void LCA(int u,int v)
    {
        if(dfn[u] < dfn[v]) swap(u,v);
        while(dfn[u] > dfn[v])
        {
            if(isbridge[u]) bcnt--;
            isbridge[u] = false;
            u = fa[u];
        }
        while(u!=v)
        {
            if(isbridge[u]) bcnt--;
            if(isbridge[v]) bcnt--;
            isbridge[u] = isbridge[v] = false;
            u = fa[u]; v = fa[v];
        }
    }
    
    void dfs(int u)
    {
        vis[u] = 1; dfn[u] = low[u] = ++dcnt;
        for(int k=head[u]; k!=-1; k=e[k].next)
            if(!e[k].used)
            {
                e[k].used = e[k^1].used = 1;
                int v = e[k].v;
                if(!vis[v])
                {
                    fa[v] = u;
                    dfs(v);
                    low[u] = min(low[u] , low[v]);
                    if(dfn[u] < low[v])
                    { bcnt++; isbridge[v] = true; }
                }
                else if(vis[v] == 1) low[u] = min(low[u],dfn[v]);
            }
        vis[u] = 2;
    }
    
    int main()
    {
        int n,m,q,cas=0;
        while(cin>>n>>m,n,m)
        {
            memset(head,-1,sizeof(head));
            int k = 0;
            for(int i=0; i<m; i++)
            {
                int u,v;
                cin>>u>>v;
                add(u,v,k);
                add(v,u,k);
            }
            memset(isbridge,false,sizeof(isbridge));
            memset(vis,0,sizeof(vis));
            dcnt = bcnt = 0;
            fa[1] = 1;
            dfs(1);
            printf("Case %d:
    ",++cas);
            cin>>q;
            while(q--)
            {
                int u,v;
                cin>>u>>v;
                LCA(u,v);
                cout<<bcnt<<endl;
            }
            cout<<endl;
        }
        return 0;
    }
  • 相关阅读:
    西山赏梅归来
    创建 WebRequest 实例并返回响应
    C# WinForm开发系列 DataGridView
    DataTable C#
    delphi 制作资源文件
    Windows Mobile上使用钩子
    OO系统分析员之路用例分析系列(7)用例规约的编写业务规则和实体描述[整理重发]
    iis下PHP5配置
    ie firefox 点flash 卡死解决方案
    PHP获取字符串编码类型
  • 原文地址:https://www.cnblogs.com/darklights/p/7642660.html
Copyright © 2011-2022 走看看