• POJ3694 Network(边双连通分量+缩点+LCA)


    题目大概是给一张图,动态加边动态求割边数。

    本想着求出边双连通分量后缩点,然后构成的树用树链剖分+线段树去维护路径上的边数和。。好像好难写。。

    看了别人的解法,这题有更简单的算法:

    在任意两点添边,那么两点路径上的边就不是割边了,于是从两点往上走到其LCA,一边缩点一边统计消失的割边数。

    这样的时间复杂度是保证的,因为最多就把所有点缩完而最多走的边数差不多就原图的边数。

    具体实现,用Tarjan求出边双连通分量后缩点;缩点用并查集,要注意合并次序深度小的作深度大的点的根;最后就是对每个询问的两个点向上走到其LCA一边走一边更新。

    另外,不必去维护缩点后的树,直接维护Tarjan算法构造的深度优先生成树就行了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define MAXN 111111
     6 #define MAXM 444444
     7 struct Edge{
     8     int v,next;
     9     bool flag;
    10 }edge[MAXM];
    11 int NE,head[MAXN];
    12 void addEdge(int u,int v){
    13     edge[NE].v=v; edge[NE].next=head[u]; edge[NE].flag=0;
    14     head[u]=NE++;
    15 }
    16 
    17 int par[MAXN];
    18 int Find(int a){
    19     while(a!=par[a]){
    20         par[a]=par[par[a]];
    21         a=par[a];
    22     }
    23     return a;
    24 }
    25 void Union(int a,int b){
    26     int pa=Find(a),pb=Find(b);
    27     if(pa==pb) return;
    28     par[pb]=pa;
    29 }
    30 
    31 int fa[MAXN],dep[MAXN],cut;
    32 int dn,dfn[MAXN],low[MAXN];
    33 void dfs(int u){
    34     dfn[u]=low[u]=++dn;
    35     for(int i=head[u]; i!=-1; i=edge[i].next){
    36         if(edge[i].flag) continue;
    37         int v=edge[i].v;
    38         if(dfn[v]){
    39             low[u]=min(low[u],dfn[v]);
    40             continue;
    41         }
    42         fa[v]=u; dep[v]=dep[u]+1;
    43         edge[i].flag=edge[i^1].flag=1;
    44         dfs(v);
    45         low[u]=min(low[u],low[v]);
    46         if(low[v]>dfn[u]) ++cut;
    47         else Union(u,v);
    48     }
    49 }
    50 
    51 int lca(int u,int v){
    52     int cnt=0;
    53     u=Find(u); v=Find(v);
    54     while(u!=v){
    55         if(dep[u]>dep[v]){
    56             Union(fa[u],u); ++cnt;
    57             u=Find(fa[u]);
    58         }else if(dep[v]>dep[u]){
    59             Union(fa[v],v); ++cnt;
    60             v=Find(fa[v]);
    61         }else{
    62             Union(fa[u],u); Union(fa[v],v); cnt+=2;
    63             u=Find(fa[u]); v=Find(fa[v]);
    64         }
    65     }
    66     return cnt;
    67 }
    68 int main(){
    69     int n,m,a,b,t=0;
    70     while(~scanf("%d%d",&n,&m) && (n||m)){
    71         NE=0;
    72         memset(head,-1,sizeof(head));
    73         while(m--){
    74             scanf("%d%d",&a,&b);
    75             addEdge(a,b); addEdge(b,a);
    76         }
    77 
    78         for(int i=1; i<=n; ++i) par[i]=i;
    79         cut=dn=0;
    80         memset(dfn,0,sizeof(dfn));
    81         dfs(1);
    82 
    83         printf("Case %d:
    ",++t);
    84         scanf("%d",&m);
    85         while(m--){
    86             scanf("%d%d",&a,&b);
    87             cut-=lca(a,b);
    88             printf("%d
    ",cut);
    89         }
    90         putchar('
    ');
    91     }
    92     return 0;
    93 }
  • 相关阅读:
    VirtualBox中的网络连接方式详解
    DRUID连接池的实用 配置详解
    redis之如何配置jedisPool参数
    怎么把myeclipse项目导入IDEA中
    最新Hadoop大数据开发学习路线图
    编程能力七段论(下)
    编程能力七段论(上)
    移动无线测试技能树
    WebView加载网页不显示图片解决办法
    编程能力七段论
  • 原文地址:https://www.cnblogs.com/WABoss/p/5154041.html
Copyright © 2020-2023  润新知