题意是给出一个连通无向图,求每次加一条边后,图内割边的数目。
最容易想到的方法是每加一条边都做一次DFS求割边,于是code之,提交,TLE。
然后上网搜了一下,看到了一个更直观的方法:设新加入的边为(u,v),先求u和v的LCA,看从LCA分别到u和v的路径上有多少条割边,然后从原图的割边数目上累减,结果就是所求,因为每加一条边,该边与DFS树上的边形成了环,环内的边就不再是割边了。这样只需要做一次DFS。
#include
<
iostream
>
using
namespace
std;
#define
MAXN 100001
#define
Min(a,b) (a<b?a:b)
int
p[MAXN],ecnt,n,m,q,T
=
1
,lowlink[MAXN],dfn[MAXN],sign,cnt,odeg[MAXN],pnt[MAXN],cutp[MAXN];
bool
cut[MAXN],visited[MAXN];
struct
Edge{
int
v,next;
}edg[
10
*
MAXN];
void
init(){
ecnt
=
0
;
memset(p,
-
1
,
sizeof
(p));
sign
=
0
;
memset(dfn,
-
1
,
sizeof
(dfn));
memset(odeg,
0
,
sizeof
(odeg));
cnt
=
0
;
memset(pnt,
-
1
,
sizeof
(pnt));
memset(cut,
false
,
sizeof
(cut));
memset(cutp,
-
1
,
sizeof
(cutp));
}
void
dfs(
int
pre,
int
u){
int
i,v;
lowlink[u]
=
dfn[u]
=++
sign;
for
(i
=
p[u];i
!=-
1
;i
=
edg[i].next){
v
=
edg[i].v;
odeg[u]
++
;
if
(dfn[v]
!=-
1
){
if
(v
!=
pre)
//
lowlink[u]
=
Min(lowlink[u],dfn[v]);
}
else
{
dfs(u,v);
pnt[v]
=
u;
lowlink[u]
=
Min(lowlink[u],lowlink[v]);
if
(dfn[u]
<
lowlink[v]){
cnt
++
;
cut[u]
=
true
;
//
存割边
edg[ecnt].next
=
cutp[u];
edg[ecnt].v
=
v;
cutp[u]
=
ecnt
++
;
}
}
}
}
void
fun(
int
u,
int
v){
//
找LCA,求LCA分别到u和v的路径上的割边数目,比较暴力
int
t,pt;
bool
find;
memset(visited,
false
,
sizeof
(visited));
int
x
=
pnt[u],y
=
pnt[v],LCA
=
0
;
//
找LCA
while
(x
!=-
1
){
visited[x]
=
true
;
x
=
pnt[x];
}
while
(y
!=-
1
){
if
(visited[y]){
LCA
=
y;
break
;
}
y
=
pnt[y];
}
if
(LCA
==
0
)
LCA
=
1
;
x
=
u,y
=
v;
do
{
if
(cut[pnt[x]]){
//
若x的双亲是某一割边的起点,则(pnt[x],x)有可能是一条割边
find
=
false
;
pt
=
t
=
cutp[pnt[x]];
while
(t
!=-
1
){
//
看x是不是属于以pnt[x]为起点的割边的终点
if
(edg[t].v
==
x){
find
=
true
;
if
(pt
==
t)
//
找到则从终点集中去掉x
cutp[pnt[x]]
=
edg[t].next;
else
edg[pt].next
=
edg[t].next;
break
;
}
pt
=
t;
t
=
edg[t].next;
}
if
(find)
cnt
--
;
if
(cutp[pnt[x]]
==-
1
)
//
终点集为空,则pnt[x]不再是割边的起点
cut[pnt[x]]
=
false
;
}
x
=
pnt[x];
}
while
(x
!=
LCA
&&
x
!=-
1
);
do
{
if
(cut[pnt[y]]){
find
=
false
;
pt
=
t
=
cutp[pnt[y]];
while
(t
!=-
1
){
if
(edg[t].v
==
y){
find
=
true
;
if
(pt
==
t)
cutp[pnt[y]]
=
edg[t].next;
else
edg[pt].next
=
edg[t].next;
break
;
}
pt
=
t;
t
=
edg[t].next;
}
if
(find)
cnt
--
;
if
(cutp[pnt[y]]
==-
1
)
cut[pnt[y]]
=
false
;
}
y
=
pnt[y];
}
while
(y
!=
LCA
&&
y
!=-
1
);
}
int
main(){
int
i,u,v;
while
(scanf(
"
%d%d
"
,
&
n,
&
m)
&&
n
&&
m){
init();
for
(i
=
0
;i
<
m;i
++
){
scanf(
"
%d%d
"
,
&
u,
&
v);
edg[ecnt].next
=
p[u];
edg[ecnt].v
=
v;
p[u]
=
ecnt
++
;
edg[ecnt].next
=
p[v];
edg[ecnt].v
=
u;
p[v]
=
ecnt
++
;
}
dfs(
-
1
,
1
);
scanf(
"
%d
"
,
&
q);
printf(
"
Case %d:\n
"
,T
++
);
for
(i
=
0
;i
<
q;i
++
){
scanf(
"
%d%d
"
,
&
u,
&
v);
fun(u,v);
printf(
"
%d\n
"
,cnt);
}
printf(
"
\n
"
);
}
return
0
;
}