hdu 2460
这是一道双联通分量的题,要用到LCA算法;
听说这个算法有两种实现方式:一个是dfs+线段树或着RMQ;一个是用tarjin;
我用的是tarjin;
题目比较简单,就是每次加了一条边之后剩下的桥的个数;
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 #define MAXN 100009 7 #pragma comment(linker,"/STACk:10240000,10240000") 8 9 int n,m,cnt,NE,BridgeNum; 10 int parent[MAXN],low[MAXN],dfn[MAXN]; 11 bool mark[MAXN],isbridge[MAXN]; 12 vector<int>ve[MAXN]; 13 14 void Tarjan(int u,int father) 15 { 16 int flag=0; 17 low[u]=dfn[u]=++cnt; 18 mark[u]=true; 19 int l=ve[u].size(); 20 for(int i=0; i<l; i++) 21 { 22 int v=ve[u][i]; 23 if(v==father&&!flag) 24 { 25 flag=1; 26 continue; 27 } 28 if(dfn[v]==0) 29 { 30 parent[v]=u; 31 Tarjan(v,u); 32 low[u]=min(low[u],low[v]); 33 if(low[v]>dfn[u]) 34 { 35 isbridge[v]=1; 36 BridgeNum++; 37 } 38 } 39 else if(mark[v]) 40 low[u]=min(low[u],dfn[v]); 41 } 42 } 43 44 void LCA(int u,int v) 45 { 46 while(dfn[u]>dfn[v]) 47 { 48 if(isbridge[u]) 49 { 50 BridgeNum--; 51 isbridge[u]=0; 52 } 53 u=parent[u]; 54 } 55 while(dfn[v]>dfn[u]) 56 { 57 if(isbridge[v]) 58 { 59 BridgeNum--; 60 isbridge[v]=0; 61 } 62 v=parent[v]; 63 } 64 while(u!=v) 65 { 66 if(isbridge[u]) 67 { 68 BridgeNum--; 69 isbridge[u]=0; 70 } 71 if(isbridge[v]) 72 { 73 BridgeNum--; 74 isbridge[v]=0; 75 } 76 u=parent[u],v=parent[v]; 77 } 78 } 79 int main() 80 { 81 int u,v,Q,ca=1; 82 while(scanf("%d%d",&n,&m)&&(n+m)) 83 { 84 BridgeNum=NE=cnt=0; 85 for(int i=0; i<=n; i++) 86 ve[i].clear(); 87 while(m--) 88 { 89 scanf("%d%d",&u,&v); 90 ve[u].push_back(v); 91 ve[v].push_back(u); 92 } 93 memset(isbridge,0,sizeof isbridge); 94 memset(dfn,0,sizeof dfn); 95 memset(mark,0,sizeof mark); 96 for(int i=1; i<=n+1; i++)parent[i]=i; 97 Tarjan(1,-1); 98 printf("Case %d:\n",ca++); 99 scanf("%d",&Q); 100 while(Q--) 101 { 102 scanf("%d%d",&u,&v); 103 LCA(u,v); 104 printf("%d\n",BridgeNum); 105 } 106 printf("\n"); 107 } 108 return 0; 109 }