zoukankan      html  css  js  c++  java
  • POJ3694 Network

    题目描述

    输入格式

    The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).

    The last test case is followed by a line containing two zeros.

    输出格式


    大致翻译:给你N个点M条边的无向图,并且有Q次加边,问每次加边之后图中的桥的数量。

    显然,如果加入的边的两个端点在同一个边双内,那么桥的数量不变。所以我们先用Tarjan对原图进行边双连通分量缩点得到一棵树。

    接着,对于两个端点不在一个边双的情况,显然桥的数量减少量等于两个端点的树上距离。我们求出树上距离,然后把两端点之间的边标记起来,即边长由原来的1改成0。每次求树上距离时就先一个个地往上爬,顺便还可以标记边。时间复杂度为O(M+QN),可以通过本题,但显然不优。

    既然边长变成0了,我们以后都没必要再管这些边了,所以我们可以用缩树的办法,用并查集把两个端点之间的点合并到一个集合中去,然后下次爬到这两个端点处时直接跳到LCA的位置就好了。

    时间复杂度为O(M+Qα(N)),接近线性

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define maxn 100010
    #define maxm 200010
    using namespace std;
    
    struct edge{
        int to,next;
        edge(){}
        edge(const int &_to,const int &_next){ to=_to,next=_next; }
    }e[maxm<<1];
    int head[maxn],k;
    
    int dep[maxn],pre[maxn],fa[maxn];
    int dfn[maxn],low[maxn],tot,stack[maxn],top;
    int uu[maxm],vv[maxm];
    int n,m,t,ans;
    
    inline void init(){
        for(register int i=0;i<=n;i++) head[i]=-1,dep[i]=dfn[i]=0;
        k=top=ans=tot=0;
    }
    inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }
    
    void tarjan_dcc(int u,int pre){
        if(dfn[u]) return;
        dfn[u]=low[u]=++tot,stack[++top]=u;
        bool flag=true;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==pre&&flag) { flag=false; continue; }
            tarjan_dcc(v,u),low[u]=min(low[u],low[v]);
        }
        if(dfn[u]==low[u]){
            while(stack[top]!=u) low[stack[top--]]=low[u];
            top--;
        }
    }
    inline void rebuild(){
        for(register int i=0;i<=n;i++) head[i]=-1; k=0;
        for(register int i=0;i<m;i++){
            int u=low[uu[i]],v=low[vv[i]];
            if(u!=v) add(u,v),add(v,u);
        }
    }
    
    void dfs(int u,int father,int deep){
        dep[u]=deep,pre[u]=u;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v!=father) dfs(v,u,deep+1),fa[v]=u,ans++;
        }
    }
    
    int get(int x){
        if(x!=pre[x]) pre[x]=get(pre[x]);
        return pre[x];
    }
    inline void getlca(int u,int v){
        u=get(u),v=get(v),top=0;
        while(u!=v){
            if(dep[u]>dep[v]) stack[++top]=u,u=get(fa[u]);
            else stack[++top]=v,v=get(fa[v]);
            ans--;
        }
        while(top) pre[stack[top--]]=u;
    }
    
    int main(){
        int T=0;
        while(~scanf("%d %d",&n,&m),n+m){
            init();
            for(register int i=0;i<m;i++){
                scanf("%d %d",&uu[i],&vv[i]);
                add(uu[i],vv[i]),add(vv[i],uu[i]);
            }
            tarjan_dcc(1,-1),rebuild();
            dfs(low[1],-1,1);
    
            scanf("%d",&t);
            printf("Case %d:
    ",++T);
            while(t--){
                int u,v; scanf("%d %d",&u,&v);
                getlca(low[u],low[v]);
                printf("%d
    ",ans);
            }
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    js的基本数据类型有哪些?
    UML 类图
    三种代理模式
    jsp 知识点
    httpServlet
    Qt时间&日期
    Microsoft visual studio C 运行时库 在 xx.exe中检测到一个错误
    C++调用COM之错
    PCL中的bug修改
    Qt使用SQLite
  • 原文地址:https://www.cnblogs.com/akura/p/10976147.html
Copyright © 2011-2022 走看看