poj3694--Network(双连通缩点+lca)

来源:互联网 发布:php弱类型 原理 编辑:程序博客网 时间:2024/04/17 06:42

poj3694:题目链接

题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量

首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少。

图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了

#include <cstdio>#include <cstring>#include <algorithm>#include <stack>using namespace std ;#define maxn 110000struct node{    int u , v ;    int next ;} edge[maxn<<2] , tree[maxn<<2] ;int head[maxn] , cnt , vis[maxn<<2] ;int h_tree[maxn] ;int dnf[maxn] , low[maxn] , time ;int belong[maxn] , degree[maxn] , num ;int fa[maxn] ;stack <int> sta ;void init(){    while( !sta.empty() ) sta.pop() ;    memset(head,-1,sizeof(head)) ;    memset(vis,0,sizeof(vis)) ;    memset(dnf,0,sizeof(dnf)) ;    memset(low,0,sizeof(low)) ;    memset(belong,0,sizeof(belong)) ;    memset(degree,0,sizeof(degree)) ;    cnt = time = num = 0 ;}void add(int u,int v){    edge[cnt].u = u ;    edge[cnt].v = v ;    edge[cnt].next = head[u] ;    head[u] = cnt++ ;}void add_tree(int u,int v) {    tree[cnt].u = u ;    tree[cnt].v = v ;    tree[cnt].next = h_tree[u] ;    h_tree[u] = cnt++ ;}void tarjan(int u){    dnf[u] = low[u] = ++time ;    int i , j , v ;    for(i = head[u] ; i != -1; i = edge[i].next)    {        if( vis[i] ) continue ;        vis[i] = vis[i^1] = 1 ;        v = edge[i].v ;        if( !dnf[v] )        {            sta.push(i) ;            tarjan(v) ;            low[u] = min(low[u],low[v]) ;            if( low[v] > dnf[u] )            {                num++ ;                while( 1 )                {                    j = sta.top() ;                    sta.pop() ;                    belong[ edge[j].v ] = num ;                    if( edge[j].u == u ) break ;                    belong[ edge[j].u ] = num ;                }            }        }        else if( dnf[v] < dnf[u] )        {            sta.push(i) ;            low[u] = min(low[u],dnf[v]) ;        }    }}void dfs(int u) {    int i , v ;    for(i = h_tree[u] ; i != -1 ; i = tree[i].next) {        v = tree[i].v ;        if( vis[v] ) continue ;        vis[v] = 1 ;        fa[v] = u ;        add(u,v) ;        dfs(v) ;    }}void get_tree(int m){    int i , u , v ;    memset(h_tree,-1,sizeof(h_tree)) ;    cnt = 0 ;    for( i = 0 ; i < m ; i++)    {        u = belong[ edge[i*2].u ] ;        v = belong[ edge[i*2].v ] ;        if( u != v )        {            add_tree(u,v) ;            add_tree(v,u) ;        }    }    memset(vis,0,sizeof(vis)) ;    memset(head,-1,sizeof(head)) ;    cnt = 0 ;    fa[1] = 0 ;    vis[1] = 1 ;    dfs(1) ;}int solve(int u,int v) {    int i , sum = 0 , flag = 0 ;    memset(low,0,sizeof(low)) ;    while( u != 0 ) {        low[u] = 1 ;        u = fa[u] ;    }    while( v != 0 ) {        if( low[v] == 0 ) {            low[v] = 1 ;        }        else {            if( flag == 0 ) {                flag = 1 ;            }            else {                low[v] = 0 ;            }        }        v = fa[v] ;    }    flag = 0 ;    for(i = 1 ; i <= num ; i++) {        if( low[i] && vis[i] )            flag = 1 ;        if( low[i] && !vis[i] ) {            vis[i] = 1 ; sum++ ;        }    }    return sum+flag ;}int main(){    int step = 0 , n , m , q , ans ;    int u , v , i , k ;    while( scanf("%d %d", &n, &m) && n+m > 0 )    {        init() ;        for(i = 0 ; i < m ; i++)        {            scanf("%d %d", &u, &v) ;            add(u,v) ;            add(v,u) ;        }        tarjan(1) ;        if( belong[1] == 0 ) {            ++num ;            for(i = 1 ; i<= n ; i++)                if( belong[i] == 0 ) belong[i] = num ;        }        get_tree(m) ;        ans = num ;        memset(vis,0,sizeof(vis)) ;        scanf("%d", &q) ;        printf("Case %d:\n", ++step) ;        while( q-- ) {            scanf("%d %d", &u, &v) ;            u = belong[u] ;            v = belong[v] ;            ans = ans - solve(u,v) + 1 ;            printf("%d\n", ans-1) ;        }    }    return 0 ;}


0 0
原创粉丝点击