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 == 0) break ;
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 }
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 == 0) break ;
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 }