zoukankan      html  css  js  c++  java
  • POJ3694 Network (板子题)

    题目链接: POJ3694 Network
    题目大意:
    一张 (N) 个点,(M) 条边的无向连通图,(Q)次操作,每次添加一条边,同时询问图中割边的数量。
    (1leq Nleq 100,000)(1leq Mleq 200,000)(1leq Qleq 1000)
    思路
    用来熟悉 (e\_DCC) 缩点的板子题。
    首先图中的边双连通分量自身不受加边的影响,割边数量为零,将它们缩点,然后就得到了一颗树,这个过程中先计算出 (ans) 的初始值。
    树上两点 (u,v) 相连时会产生环,相当于 (u)(v) 的路径上的所有割边都不再是割边,具体来说就是两个节点分别向 (lca) 跳,并将途中的割边标记为普通边。
    考虑到要多次对树进行操作,可以使用并查集记录一个点向上的第一条割边的位置,当其变成普通边后,将子节点合并到父节点中,同时 (ans--)
    动态查询 (O(M+NlogN)) ,离线 (O(M+N)) 。( (LCA) 实现不同)

    可能会有人对于直接在树上标记这个操作有疑问,因为实际上树加了边后形态就变了,但其实仔细想一想会发现这是合理的,跳并查集的过程其实就是略过所有非割边的边,相当于从一个新的 (e\_DCC) 中直接跳出来,到剩下的割边上,而合并并查集的过程就是合并两个 (e\_DCC) 的过程,算法正确性没有问题。

    细节:

    • 求割边的时候记录边,不记录父亲
    • 因为是多组数据,有一堆鬼畜的初始化,要注意一些
    • 1Y的,在POJ Best Solutions上面竟然进了前两页,非常感动

    Code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 100100
    #define M 200100
    #define LOG 17
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return s*w;
    }
    int head[N],to[M*2],nxt[M*2]; //原图
    int H[N],T[M*2],NX[M*2]; //缩点后的图
    int dfn[N],low[N],c[N]; //c[i]:i所在的e_DCC编号
    int f[N][LOG],dep[N];
    int fa[N];
    int cnt,num,dcc,t_e; //cnt:原图边计数 num:时间戳计数 dcc:e_DCC计数 t_e:新图计数
    int n,m,ans;
    bool bridge[M*2];
    void init(int n){
        mem(head,-1),mem(H,-1);
        mem(dfn,0),mem(c,0);
        mem(bridge,false);
        for(int i=1;i<=n;i++)fa[i]=i;
        cnt=t_e=-1,ans=dcc=num=0;
    }
    void add_e(int a,int b,bool id){
        nxt[++cnt]=head[a];
        head[a]=cnt;
        to[cnt]=b;
        if(id)add_e(b,a,0);
    }
    void add_c(int a,int b){
        NX[++t_e]=H[a],H[a]=t_e,T[t_e]=b;
    }
    void tarjan(int x,int e){
        dfn[x]=low[x]=++num;
        for(int i=head[x];~i;i=nxt[i]){
            if(i==(e^1))continue;
            int y=to[i];
            if(dfn[y])low[x]=min(low[x],dfn[y]);
            else{
                tarjan(y,i);
                low[x]=min(low[x],low[y]);
                if(low[y]>dfn[x]){
                    bridge[i]=bridge[i^1]=true,ans++;
                }
            }
        }
    }
    void dfs1(int x){
        c[x]=dcc;
        for(int i=head[x];~i;i=nxt[i]){
            if(c[to[i]]||bridge[i])continue;
            dfs1(to[i]);
        }
    }
    void dfs2(int x,int fath){
        f[x][0]=fath,dep[x]=dep[fath]+1;
        for(int i=1;i<LOG;i++){
            f[x][i]=f[f[x][i-1]][i-1];
        }
        for(int i=H[x];~i;i=NX[i]){
            if(T[i]==fath)continue;
            dfs2(T[i],x);
        }
    }
    int Lca(int a,int b){
        if(dep[a]<dep[b])swap(a,b);
        for(int i=LOG-1;i>=0;i--)
            if(f[a][i]&&dep[f[a][i]]>=dep[b])a=f[a][i];
        if(a==b)return a;
        for(int i=LOG-1;i>=0;i--)
            if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
        return f[a][0];
    }
    int find(int x){
        if(fa[x]==x)return x;
        return fa[x]=find(fa[x]);
    }
    int main(){
        int a,b,q,lca,T=1;
        while((n=read())|(m=read())){
            init(n);
            for(int i=0;i<m;i++)
                add_e(read(),read(),1);
            tarjan(1,-1);
            for(int i=1;i<=n;i++)
                if(!c[i])++dcc,dfs1(i);
            for(int i=0;i<=cnt;i++){
                int u=to[i],v=to[i^1];
                if(c[u]==c[v])continue;
                add_c(c[u],c[v]);
            }
            dfs2(1,0);
            printf("Case %d:
    ",T++);
            q=read();
            while(q--){
                a=c[read()],b=c[read()];
                lca=Lca(a,b);
                a=find(a),b=find(b);
                while(dep[a]>dep[lca])
                    fa[a]=find(f[a][0]), a=find(a),ans--;
                while(dep[b]>dep[lca])
                    fa[b]=find(f[b][0]), b=find(b),ans--;
                printf("%d
    ",ans);
            }
            puts("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    python之pymysql的使用
    python 之 Apollo
    python 之 RabbitMQ
    python之内置sqlite3
    pyQt5之2048小游戏
    VSCode 下载速度慢问题解决
    Redis 缓存穿透 + 缓存雪崩 + 缓存击穿的原因和解决方案
    部门优化
    Cpu_Limit.sh
    Autoback-xtraback.sh
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14329737.html
Copyright © 2011-2022 走看看