题意:给n个点和m条边,再给出q条边,问每次加一条边以后剩下多少桥。

  分析:这题是结合了LCA和dfn的妙用。_dfn数组和dfn的意义不一样,并非访问的时间戳,_dfn表示的是被访问的顺序,而且是多线程访问下的顺序,举个例子,同一个点分岔开来的点,距离这个点相同距离的点,他们的_dfn的值是相同的,而dfn不是,类似于单线程dfs访问的各点的dfn值是不同的。

  具体见代码:  

 

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <map>
  5 #include <vector>
  6 #include <queue>
  7 using namespace std;
  8 const int N = 100000 + 5;
  9 
 10 int n,m,tot,head[N],cnt,dfs_clock,dfn[N],_dfn[N],root[N],low[N];
 11 bool bridge[N];
 12 struct edge
 13 {
 14     int nxt,v;
 15 }edges[N<<2];
 16 
 17 void init()
 18 {
 19     tot = 0,dfs_clock = 0,cnt = 0;
 20     memset(head,-1,sizeof(head));
 21     memset(dfn,0,sizeof(dfn));
 22     memset(_dfn,0,sizeof(_dfn));
 23     memset(bridge,false,sizeof(bridge));
 24     for(int i=1;i<=n;i++) root[i] = i;
 25 }
 26 
 27 void addEdge(int u,int v)
 28 {
 29     edges[tot] = (edge){head[u],v};
 30     head[u] = tot ++;
 31     edges[tot] = (edge){head[v],u};
 32     head[v] = tot ++;
 33 }
 34 
 35 void tarjan(int u)
 36 {
 37     dfn[u] = low[u] = ++dfs_clock;
 38     _dfn[u] = _dfn[root[u]] + 1;
 39     for(int i=head[u];i!=-1;i=edges[i].nxt)
 40     {
 41         edge &e = edges[i];
 42         int v = e.v;
 43         if(!dfn[v])
 44         {
 45             root[v] = u;
 46             tarjan(v);
 47             low[u] = min(low[u],low[v]);
 48             if(low[v] > dfn[u])
 49             {
 50                 cnt ++;
 51                 bridge[v] = true;
 52             }
 53         }
 54         else if(dfn[v] < dfn[u] && v!=root[u]) low[u] = min(low[u],dfn[v]);
 55     }
 56 }
 57 
 58 void LCA(int u,int v)
 59 {
 60     while(_dfn[u] > _dfn[v])
 61     {
 62         if(bridge[u])
 63         {
 64             cnt --;
 65             bridge[u]  = false;
 66         }
 67         u = root[u];
 68     }
 69     while(_dfn[u] < _dfn[v])
 70     {
 71         if(bridge[v])
 72         {
 73             cnt --;
 74             bridge[v] = false;
 75         }
 76         v = root[v];
 77     }
 78     while(u != v)
 79     {
 80         if(bridge[u])
 81         {
 82             cnt --;
 83             bridge[u] = false;
 84         }
 85         if(bridge[v])
 86         {
 87             cnt --;
 88             bridge[v] = false;
 89         }
 90         u = root[u];
 91         v = root[v];
 92     }
 93 }
 94 
 95 void solve()
 96 {
 97     for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
 98 
 99     int q;scanf("%d",&q);
100     while(q--)
101     {
102         int u,v;scanf("%d%d",&u,&v);
103         LCA(u,v);
104         printf("%d\n",cnt);
105     }
106     puts("");
107 }
108 
109 int main()
110 {
111     int kase = 1;
112     while(scanf("%d%d",&n,&m)==2)
113     {
114         if(n==0 && m==0) break;
115         init();
116         printf("Case %d:\n",kase++);
117         while(m--)
118         {
119             int u,v;scanf("%d%d",&u,&v);
120             addEdge(u,v);
121         }
122         solve();
123     }
124 }