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 }
posted @ 2012-10-18 15:59  Szz  阅读(339)  评论(0编辑  收藏  举报