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 ;
}