poj 3694 Network 边双连通分量+LCA

题意:一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥


分析:先跑一边tarjan把所有的桥边求出来,同时建好深搜树。没加入一条边也就是说在树上这两个点之间的路径和该边构成一个环,也就是这两点的路径上的边都不是桥边了,那么就跑一边双循环爆推LCA把这些边删掉就好了。


代码:

var
  e,tot,t,n,m,step:longint;
  side:array[1..1000000] of record
    x,y,next:longint;
  end;
  dfn,low,f,last:array[1..100000] of longint;
  v:array[1..100000] of boolean;

procedure add(x,y:longint);
begin
  inc(e);
  side[e].x:=x; side[e].y:=y; side[e].next:=last[x]; last[x]:=e;
  inc(e);
  side[e].x:=y; side[e].y:=x; side[e].next:=last[y]; last[y]:=e;
end;

procedure init;
var
  i,x,y:longint;
begin
  e:=0;
  fillchar(last,sizeof(last),0);
  for i:=1 to m do
  begin
    readln(x,y);
    add(x,y);
  end;
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

procedure tarjan(x,fa:longint);
var
  i:longint;
begin
  inc(t);
  dfn[x]:=t;
  low[x]:=t;
  i:=last[x];
  while i>0 do
    with side[i] do
    begin
      if y<>fa then
        if dfn[y]=0
          then begin
                 f[y]:=i;
                 tarjan(y,x);
                 if low[y]>dfn[x] then
                 begin
                   inc(tot);
                   v[y]:=true;
                 end;
                 low[x]:=min(low[y],low[x]);
               end
          else low[x]:=min(dfn[y],low[x]);
      i:=next;
    end;
end;

procedure lca(x,y:longint);
begin
  if dfn[x]<dfn[y] then
  begin
    x:=x xor y; y:=x xor y; x:=x xor y;
  end;
  while dfn[x]>dfn[y] do
  begin
    if v[x] then
    begin
      dec(tot);
      v[x]:=false;
    end;
    x:=side[f[x]].x;
  end;
  while y<>x do
  begin
    if v[y] then
    begin
      dec(tot);
      v[y]:=false;
    end;
    y:=side[f[y]].x;
  end;
end;

procedure main;
var
  i,q,x,y:longint;
begin
  fillchar(dfn,sizeof(dfn),0);
  fillchar(low,sizeof(low),0);
  fillchar(v,sizeof(v),false);
  t:=0;
  tot:=0;
  for i:=1 to n do
    if dfn[i]=0 then tarjan(i,0);
  readln(q);
  for i:=1 to q do
  begin
    readln(x,y);
    lca(x,y);
    writeln(tot);
  end;
end;

begin
  readln(n,m);
  while not eof do
  begin
    init;
    inc(step);
    writeln('Case ',step,':');
    main;
    writeln;
    readln(n,m);
  end;
end.


你可能感兴趣的:(poj 3694 Network 边双连通分量+LCA)