题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥。一个最容易想到的办法就是先加边找桥,加边找桥,这样可定超时。那么就可以缩点,因为如果一条边不是桥那么无论怎么加边他肯定都不会变成桥,这样我吧不是桥的点缩成一个点。这样全图就都是桥,这样的话,我们就在加的遍里面去找如果加的边是同一个点,那么,肯定不会减少桥,但是如果不是同一个,那么桥肯定减少~。
代码如下:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <vector> 7 #include <queue> 8 #define loop(s,i,n) for(i = s;i < n;i++) 9 #define cl(a,b) memset(a,b,sizeof(a)) 10 using namespace std; 11 const int maxn = 100005; 12 int low[maxn],dfn[maxn],set[maxn],father[maxn],dfsclock,cut; 13 vector<int >g[maxn]; 14 int find(int x) 15 { 16 if(set[x] != x) 17 set[x] = find(set[x]); 18 19 return set[x]; 20 } 21 int merge(int x,int y) 22 { 23 x = find(x); 24 y = find(y); 25 if(y != x) 26 { 27 set[y] = x; 28 return 1; 29 } 30 return 0; 31 } 32 33 void tarjan(int u,int pre) 34 { 35 int v,i,j; 36 dfn[u] = low[u] = ++dfsclock; 37 loop(0,i,g[u].size()) 38 { 39 v = g[u][i]; 40 if(!dfn[v]) 41 { 42 tarjan(v,u); 43 father[v] = u; 44 low[u] = min(low[v],low[u]); 45 if(low[v] > dfn[u]) 46 cut++; 47 else 48 merge(u,v); 49 } 50 else if(v != pre) 51 low[u] = min(low[u],dfn[v]); 52 } 53 } 54 void lca(int u,int v) 55 { 56 57 while(u != v) 58 { 59 while(dfn[u] >= dfn[v] && u != v) 60 { 61 if(merge(u,father[u])) 62 cut--; 63 u = father[u]; 64 } 65 while(dfn[v] >= dfn[u] && u != v) 66 { 67 if(merge(v,father[v])) 68 cut--; 69 v = father[v]; 70 } 71 } 72 } 73 int main() 74 { 75 int n,m; 76 int i,x,y,cas = 0; 77 while(scanf("%d %d", &n,&m)&&(n||m)) 78 { 79 int u,v; 80 printf("Case %d: ",++cas); 81 loop(1,i,n+1) 82 { 83 g[i].clear(); 84 set[i] = i; 85 father[i] = 0; 86 } 87 while(m--) 88 { 89 scanf("%d %d",&u,&v); 90 g[u].push_back(v); 91 g[v].push_back(u); 92 93 } 94 cl(dfn,0); 95 cl(low,0); 96 cut = dfsclock = 0; 97 98 int k; 99 scanf("%d",&k); 100 tarjan(1,-1); 101 102 while(k--) 103 { 104 scanf("%d %d",&u,&v); 105 lca(u,v); 106 printf("%d ",cut); 107 } 108 puts(""); 109 } 110 return 0; 111 }