http://poj.org/problem?id=3694
题意:
给一幅图,若干个操作,每个操作时连接两个点,对于每个操作之后的图判断图中还有几条割边
题解 : tarjan + lca ;
//将不是割边上的点缩为一个点,然后统计割边,求添加一条边之后,割边减少了多少,就是从两个点出发
//到达他们最近的公共祖先,他们经过了几条割边,然后减去经过的割边数,就是答案,这里用到了lca
//并查集
1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<
set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<
string>
11
#define Min(a,b) a<b?a:b
12
#define Max(a,b) a>b?a:b
13
#define CL(a,num) memset(a,num,sizeof(a));
14
#define eps 1e-6
15
#define inf 10001000
16
17
#define ll __int64
18
19
#define read() freopen("data.txt","r",stdin) ;
20
#define inf 9999999
21
using
namespace std;
22
23
const
double pi = acos(-
1.0);
24
const
int maxn =
100010;
25
#define N 30
26
int n , m ;
27
int dfn[maxn];
//
记录 入栈的次序;
28
int low[maxn];
//
记录 最小的 可以到达 的次序
29
int stack[maxn] ;
//
栈
30
int instack[maxn];
//
记录 是否在栈中
31
int num ;
//
入栈的次序
32
int top;
//
栈顶
33
int bcnt ;
//
所点的 代表 序号
34
int belong[maxn];
//
记录每个节点所属 的 缩点号;
35
vector<
int>g[maxn] ;
36
int ans[maxn] ;
37
int
in[maxn],
out[maxn] ;
38
int f[maxn],father[maxn] ;
39
int cut ;
40
int find(
int x)
41 {
42
if(f[x]!=x) f[x] = find(f[x]) ;
43
return f[x] ;
44 }
45
int link(
int i,
int j)
//
判断是否在同一个 缩点 里面
46
{
47
int a = find(i) ;
48
int b = find(j) ;
49
if(a!=b)
50 {
51 f[a] = b;
52
return
1 ;
53 }
54
55
return
0 ;
56 }
57
void tarjan(
int a,
int pre)
58 {
59
int j ,i, k;
60 dfn[a] = low[a]= ++num ;
61
62 stack[++top] = a;
63 instack[a] =
1 ;
64
for(i =
0 ; i < g[a].size();i++)
65 {
66
int k = g[a][i] ;
67
if(!dfn[k])
68 {
69 tarjan(k,a) ;
70
71 father[k] = a ;
72
73
if(low[a] > low[k]) low[a] = low[k] ;
74
75
if(low[k] > dfn[a])cut ++ ;
76
else
77 link(a,k) ;
//
将 不是 割边上的点 缩成一个点 ;
78
79 }
80
else
81 {
82
if(k != pre &&instack[k] && dfn[k] < low[a]) low[a] = dfn[k] ;
//
这里不能为 父节点
83
}
84
85 }
86
87
88
89 }
90
91
void init()
92 {
93
94 CL(instack,
0);
95 CL(belong,
0) ;
96 CL(dfn,
0) ;
97 CL(low,
0) ;
98 CL(father,
0) ;
99 num = bcnt = top =
0 ;
100
101
for(
int i =
0 ;i <=n;i++)f[i] = i ;
102
103
104
105 }
106
107
void lca(
int u,
int v)
//
最近公共祖先 模版
108
{
109
while(u!=v)
110 {
111
112
while(dfn[u] > dfn[v] && u!=v)
113 {
114
if(link(u,father[u])) cut--;
115
else u = father[u] ;
116 }
117
while(dfn[v] > dfn[u]&& u!=v)
118 {
119
if(link(v,father[v])) cut-- ;
120
else v = father[v] ;
121
122 }
123
124 }
125 }
126
int main()
127 {
128
int i ,a,b,t,j,mi,mx;
129
int cas =
0 ;
130
//
read() ;
131
132
while(scanf(
"
%d%d
",&n,&m)!=EOF)
133 {
134
if(n ==
0&& m ==
0)
break ;
135
136 init() ;
137
138
for(i =
0;i <= n;i++) g[i].clear() ;
139
140
for(i =
0 ; i < m;i++)
141 {
142 scanf(
"
%d%d
",&a,&b);
143 g[a].push_back(b);
144 g[b].push_back(a) ;
145 }
146 cut =
0 ;
147 tarjan(
1,-
1) ;
148 scanf(
"
%d
",&t);
149
150 printf(
"
Case %d:\n
",++cas) ;
151
while(t--)
152 {
153 scanf(
"
%d%d
",&a,&b);
154 lca(a,b) ;
155
156 printf(
"
%d\n
",cut) ;
157 }
158 printf(
"
\n
") ;
159
160 }
161
162 }