poj 3694 Network (无向图的 割边 lca )

http://poj.org/problem?id=3694


题意:

   

给一幅图,若干个操作,每个操作时连接两个点,对于每个操作之后的图判断图中还有几条割边
  题解 :  tarjan  + lca ;

//将不是割边上的点缩为一个点,然后统计割边,求添加一条边之后,割边减少了多少,就是从两个点出发
//到达他们最近的公共祖先,他们经过了几条割边,然后减去经过的割边数,就是答案,这里用到了lca
//并查集
 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include< set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include< string>
 11  #define Min(a,b) a<b?a:b
 12  #define Max(a,b) a>b?a:b
 13  #define CL(a,num) memset(a,num,sizeof(a));
 14  #define eps  1e-6
 15  #define inf 10001000
 16 
 17  #define ll   __int64
 18 
 19  #define  read()  freopen("data.txt","r",stdin) ;
 20  #define inf  9999999
 21  using  namespace std;
 22 
 23  const  double pi  = acos(- 1.0);
 24  const  int maxn =  100010;
 25  #define N  30
 26  int n , m ;
 27  int dfn[maxn]; //  记录 入栈的次序;
 28  int low[maxn]; //  记录 最小的 可以到达 的次序
 29  int stack[maxn] ; //
 30  int  instack[maxn]; // 记录 是否在栈中
 31  int num ; //   入栈的次序
 32  int top;   //  栈顶
 33  int  bcnt ;   //  所点的 代表 序号
 34  int belong[maxn]; //   记录每个节点所属 的 缩点号;
 35  vector< int>g[maxn] ;
 36  int ans[maxn] ;
 37  int  in[maxn], out[maxn] ;
 38  int f[maxn],father[maxn] ;
 39  int cut ;
 40  int find( int x)
 41 {
 42      if(f[x]!=x) f[x] = find(f[x]) ;
 43      return f[x] ;
 44 }
 45  int link( int i, int  j) //  判断是否在同一个 缩点 里面
 46  {
 47      int a = find(i) ;
 48      int b = find(j) ;
 49      if(a!=b)
 50     {
 51         f[a] = b;
 52          return  1 ;
 53     }
 54 
 55      return  0 ;
 56 }
 57  void tarjan( int a, int pre)
 58 {
 59      int j ,i, k;
 60     dfn[a] = low[a]= ++num ;
 61 
 62     stack[++top] = a;
 63     instack[a] =  1 ;
 64      for(i =  0 ; i < g[a].size();i++)
 65     {
 66          int k = g[a][i] ;
 67          if(!dfn[k])
 68         {
 69             tarjan(k,a) ;
 70 
 71             father[k] = a ;
 72 
 73              if(low[a] > low[k]) low[a] = low[k] ;
 74 
 75              if(low[k] > dfn[a])cut ++ ;
 76              else
 77               link(a,k) ;  //  将 不是 割边上的点 缩成一个点 ;
 78 
 79         }
 80          else
 81         {
 82              if(k != pre &&instack[k] && dfn[k] < low[a]) low[a] = dfn[k] ; //   这里不能为 父节点
 83          }
 84 
 85     }
 86 
 87 
 88 
 89 }
 90 
 91  void init()
 92 {
 93 
 94     CL(instack, 0);
 95     CL(belong, 0) ;
 96     CL(dfn, 0) ;
 97     CL(low, 0) ;
 98     CL(father, 0) ;
 99     num = bcnt = top  =  0 ;
100 
101      for( int i =  0 ;i <=n;i++)f[i] = i ;
102 
103 
104 
105 }
106 
107  void  lca( int u, int v) //  最近公共祖先 模版
108  {
109      while(u!=v)
110     {
111 
112          while(dfn[u] > dfn[v] && u!=v)
113         {
114              if(link(u,father[u])) cut--;
115              else  u = father[u] ;
116         }
117          while(dfn[v] > dfn[u]&& u!=v)
118         {
119              if(link(v,father[v])) cut-- ;
120              else v = father[v] ;
121 
122         }
123 
124     }
125 }
126  int  main()
127 {
128      int i ,a,b,t,j,mi,mx;
129      int cas =  0 ;
130      // read() ;
131 
132      while(scanf( " %d%d ",&n,&m)!=EOF)
133     {
134          if(n ==  0&& m ==  0break ;
135 
136         init() ;
137 
138          for(i =  0;i <= n;i++) g[i].clear() ;
139 
140          for(i = 0  ; i < m;i++)
141         {
142             scanf( " %d%d ",&a,&b);
143             g[a].push_back(b);
144             g[b].push_back(a) ;
145         }
146         cut =  0 ;
147         tarjan( 1,- 1) ;
148         scanf( " %d ",&t);
149 
150         printf( " Case %d:\n ",++cas) ;
151          while(t--)
152         {
153             scanf( " %d%d ",&a,&b);
154             lca(a,b) ;
155 
156             printf( " %d\n ",cut) ;
157         }
158         printf( " \n ") ;
159 
160     }
161 
162 }

你可能感兴趣的:(NetWork)