poj3694--Network(双连通缩点+lca)
poj3694:题目链接
题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量
首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少。
图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std ; #define maxn 110000 struct 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 ; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。