题目大意是:对于(n, m)的图,给定边a, b查询从a到b要经过的割点的最少数目。
先tarjan算法求双连通然后缩点,即对于每个割点将周围的每个双连通看成一个点与之相连。然后求解LCA即可,距离dis[u]表示从根出发到u的遍历过程中经过的割顶的数目,利用
tarjan离线算法, 最后答案是:dis[u] + dis[v] - 2*dis[findset(v)] + (findset(v) > bcc_cnt)。注意findset(v) > bcc_cnt表示当LCA(u,v) 为割顶时的判断,此时必须加1。
代码:
1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <climits> 5 #include <cstring> 6 #include <cstdlib> 7 #include <string> 8 #include <stack> 9 #include <map> 10 #include <cmath> 11 #include <vector> 12 #include <queue> 13 #include <algorithm> 14 #define esp 1e-6 15 #define pi acos(-1.0) 16 #define pb push_back 17 #define lson l, m, rt<<1 18 #define rson m+1, r, rt<<1|1 19 #define mp(a, b) make_pair((a), (b)) 20 #define in freopen("in.txt", "r", stdin); 21 #define out freopen("out.txt", "w", stdout); 22 #define print(a) printf("%d\n",(a)); 23 #define bug puts("********))))))"); 24 #define stop system("pause"); 25 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 26 #define inf 0x0f0f0f0f 27 28 using namespace std; 29 typedef long long LL; 30 typedef vector<int> VI; 31 typedef pair<int, int> pii; 32 typedef vector<pii> VII; 33 typedef vector<pii, int> VIII; 34 typedef VI:: iterator IT; 35 #define eid first 36 #define vtx second 37 38 const int maxn = 10000 + 10000; 39 const int maxm = 100000 + 10000; 40 int pre[maxn], low[maxn], bccno[maxn], ebccno[maxm], iscut[maxn], vis[maxm], ans[maxn], pa[maxn], bcc_cnt, dfs_clock; 41 VI g[maxn], bcc[maxn]; 42 VII adj[maxn], query[maxn]; 43 struct edge{ 44 int u, v; 45 } ee[maxm]; 46 stack<int> S; 47 48 int dfs(int u, int fa) 49 { 50 int lowu = pre[u] = ++dfs_clock; 51 int child = 0; 52 for(int i = 0; i < adj[u].size(); i++) 53 { 54 int v = adj[u][i].vtx; 55 if(!pre[v]) 56 { 57 S.push(adj[u][i].eid); 58 child++; 59 vis[adj[u][i].eid] = 1; 60 int lowv = dfs(v, u); 61 lowu = min(lowu, lowv); 62 if(lowv >= pre[u]) 63 { 64 iscut[u] = 1; 65 bcc_cnt++; 66 bcc[bcc_cnt].clear(); 67 for(;;) 68 { 69 int e = S.top(); S.pop(); 70 bcc[bcc_cnt].pb(e); 71 ebccno[e] = bcc_cnt; 72 bccno[ee[e].u] = bccno[ee[e].v] = bcc_cnt; 73 if(e == adj[u][i].eid) break; 74 } 75 } 76 } 77 else if(pre[v] < pre[u]) 78 { 79 if(v != fa) 80 { 81 lowu = min(lowu, pre[v]); 82 S.push(adj[u][i].eid); 83 vis[adj[u][i].eid] = 1; 84 } 85 else { 86 if( !vis[adj[u][i].eid]) 87 { 88 lowu = min(lowu, pre[v]); 89 S.push(adj[u][i].eid); 90 vis[adj[u][i].eid] = 1; 91 } 92 } 93 } 94 } 95 if(fa < 0 && child == 1) 96 { 97 iscut[u] = 0; 98 } 99 return low[u] = lowu; 100 } 101 void find_bcc(int n) 102 { 103 memset(pre, 0, sizeof(pre)); 104 memset(bccno, 0, sizeof(bccno)); 105 memset(iscut, 0, sizeof(iscut)); 106 memset(ebccno, 0, sizeof(ebccno)); 107 memset(vis, 0, sizeof(vis)); 108 109 while(!S.empty()) S.pop(); 110 dfs_clock = bcc_cnt = 0; 111 for(int i = 0; i < n ;i++) 112 if(!pre[i]) 113 dfs(i, -1); 114 } 115 int flag[maxn]; 116 int dis[maxn]; 117 int vv[maxn]; 118 int findset(int x) 119 { 120 return pa[x] == x ? x : pa[x] = findset(pa[x]); 121 } 122 void tarjan(int u, int d) 123 { 124 vv[u] = 1; 125 dis[u] = d; 126 pa[u] = u; 127 if(u > bcc_cnt) 128 dis[u]++; 129 for(int i = 0; i < query[u].size(); i++) 130 { 131 int v = query[u][i].first; 132 int id = query[u][i].second; 133 if(vis[v]) 134 ans[id] = dis[u] + dis[v] - 2*dis[findset(v)] + (findset(v) > bcc_cnt); 135 } 136 for(int i = 0; i < g[u].size(); i++) 137 { 138 int v = g[u][i]; 139 if(!vv[v]) 140 { 141 tarjan(v, dis[u]); 142 pa[v] = u; 143 } 144 } 145 } 146 int main(void) 147 { 148 int n, m; 149 while(scanf("%d%d", &n, &m), n||m) 150 { 151 for(int i = 0; i < maxn; i++) 152 adj[i].clear(), g[i].clear(), query[i].clear(); 153 memset(flag, -1, sizeof(flag)); 154 for(int i = 1; i <= m; i++) 155 { 156 int u, v; 157 scanf("%d%d", &u, &v); 158 u--, v--; 159 adj[u].pb(mp(i, v)); 160 adj[v].pb(mp(i, u)); 161 ee[i].u = u, ee[i].v = v; 162 } 163 find_bcc(n); 164 int cut_cnt = 0; 165 for(int i = 0; i < n; i++) 166 if(iscut[i]) 167 { 168 cut_cnt++; 169 int u = cut_cnt+bcc_cnt; 170 for(int k = 0; k < adj[i].size(); k++) 171 { 172 int v = ebccno[adj[i][k].first]; 173 if(flag[v] != u ) 174 { 175 flag[v] = u; 176 g[v].pb(u); 177 g[u].pb(v); 178 } 179 } 180 } 181 int q; 182 for(int i = scanf("%d", &q); i <= q; i++) 183 { 184 int s, t; 185 scanf("%d%d", &s, &t); 186 s = ebccno[s], t = ebccno[t]; 187 query[s].pb(mp(t, i)); 188 query[t].pb(mp(s, i)); 189 } 190 memset(vv, 0, sizeof(vv)); 191 for(int i = 1; i <= bcc_cnt+cut_cnt; i++) 192 if(!vv[i]) 193 tarjan(i, 0); 194 for(int i = 1; i <= q; i++) 195 printf("%d\n", ans[i]); 196 } 197 return 0; 198 }
这个也可用Sparse Table(ST算法)结合RMQ求解LCA
下面是代码:
1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <climits> 5 #include <cstring> 6 #include <cstdlib> 7 #include <string> 8 #include <stack> 9 #include <map> 10 #include <cmath> 11 #include <vector> 12 #include <queue> 13 #include <algorithm> 14 #define esp 1e-6 15 #define pi acos(-1.0) 16 #define pb push_back 17 #define lson l, m, rt<<1 18 #define rson m+1, r, rt<<1|1 19 #define mp(a, b) make_pair((a), (b)) 20 #define in freopen("in.txt", "r", stdin); 21 #define out freopen("out.txt", "w", stdout); 22 #define print(a) printf("%d\n",(a)); 23 #define bug puts("********))))))"); 24 #define stop system("pause"); 25 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 26 #define inf 0x0f0f0f0f 27 28 using namespace std; 29 typedef long long LL; 30 typedef vector<int> VI; 31 typedef pair<int, int> pii; 32 typedef vector<pii> VII; 33 typedef vector<pii, int> VIII; 34 typedef VI:: iterator IT; 35 #define eid first 36 #define vtx second 37 38 const int maxn = 10000 + 10000; 39 const int maxm = 100000 + 10000; 40 int pre[maxn], low[maxn], bccno[maxn], ebccno[maxm], iscut[maxn], vis[maxm], ans[maxn], pa[maxn], bcc_cnt, dfs_clock; 41 int dep[maxn], E[maxn], R[maxn]; 42 int dp[maxn*2][30]; 43 VI g[maxn], bcc[maxn]; 44 VII adj[maxn], query[maxn]; 45 struct edge 46 { 47 int u, v; 48 } ee[maxm]; 49 stack<int> S; 50 int cnt; 51 int dfs(int u, int fa) 52 { 53 int lowu = pre[u] = ++dfs_clock; 54 int child = 0; 55 for(int i = 0; i < adj[u].size(); i++) 56 { 57 int v = adj[u][i].vtx; 58 if(!pre[v]) 59 { 60 S.push(adj[u][i].eid); 61 child++; 62 vis[adj[u][i].eid] = 1; 63 int lowv = dfs(v, u); 64 lowu = min(lowu, lowv); 65 if(lowv >= pre[u]) 66 { 67 iscut[u] = 1; 68 bcc_cnt++; 69 bcc[bcc_cnt].clear(); 70 for(;;) 71 { 72 int e = S.top(); 73 S.pop(); 74 bcc[bcc_cnt].pb(e); 75 ebccno[e] = bcc_cnt; 76 bccno[ee[e].u] = bccno[ee[e].v] = bcc_cnt; 77 if(e == adj[u][i].eid) break; 78 } 79 } 80 } 81 else if(pre[v] < pre[u]) 82 { 83 if(v != fa) 84 { 85 lowu = min(lowu, pre[v]); 86 S.push(adj[u][i].eid); 87 vis[adj[u][i].eid] = 1; 88 } 89 else 90 { 91 if( !vis[adj[u][i].eid]) 92 { 93 lowu = min(lowu, pre[v]); 94 S.push(adj[u][i].eid); 95 vis[adj[u][i].eid] = 1; 96 } 97 } 98 } 99 } 100 if(fa < 0 && child == 1) 101 { 102 iscut[u] = 0; 103 } 104 return low[u] = lowu; 105 } 106 void find_bcc(int n) 107 { 108 memset(pre, 0, sizeof(pre)); 109 memset(bccno, 0, sizeof(bccno)); 110 memset(iscut, 0, sizeof(iscut)); 111 memset(ebccno, 0, sizeof(ebccno)); 112 memset(vis, 0, sizeof(vis)); 113 114 while(!S.empty()) S.pop(); 115 dfs_clock = bcc_cnt = 0; 116 for(int i = 0; i < n ; i++) 117 if(!pre[i]) 118 dfs(i, -1); 119 } 120 int flag[maxn]; 121 int dis[maxn]; 122 int vv[maxn]; 123 int findset(int x) 124 { 125 return pa[x] == x ? x : pa[x] = findset(pa[x]); 126 } 127 void ST(int u, int d, int sum) 128 { 129 vv[u] = 1; 130 R[u] = ++cnt; 131 dep[cnt] = d; 132 E[cnt] = u; 133 dis[u] = sum; 134 if(u > bcc_cnt) 135 dis[u]++; 136 for(int i = 0; i < g[u].size(); i++) 137 { 138 int v = g[u][i]; 139 if(!vv[v]) 140 { 141 ST(v, d+1, dis[u]); 142 E[++cnt] = u; 143 dep[cnt] = d; 144 } 145 } 146 } 147 void Init(void) 148 { 149 for(int i = 1; i <= cnt; i++) 150 dp[i][0] = i; 151 for(int j = 1; j <= (int)(log(cnt)/log(2.0)); j++) 152 for(int i = 1; i + (1<<j) - 1 <= cnt; i++) 153 { 154 if(dep[dp[i][j-1]] < dep[dp[i+(1<<(j-1))][j-1]]) 155 dp[i][j] = dp[i][j-1]; 156 else dp[i][j] = dp[i + (1<<(j-1))][j-1]; 157 } 158 } 159 int RMQ(int u, int v) 160 { 161 int k = (int)(log(v - u + 1)/log(2.0)); 162 if(dep[dp[u][k]] < dep[dp[v - (1<<k) + 1][k]]) 163 return dp[u][k]; 164 return dp[v - (1<<k) + 1][k]; 165 } 166 int main(void) 167 { 168 169 int n, m; 170 while(scanf("%d%d", &n, &m), n||m) 171 { 172 for(int i = 0; i < maxn; i++) 173 adj[i].clear(), g[i].clear(), query[i].clear(); 174 memset(flag, -1, sizeof(flag)); 175 for(int i = 1; i <= m; i++) 176 { 177 int u, v; 178 scanf("%d%d", &u, &v); 179 u--, v--; 180 adj[u].pb(mp(i, v)); 181 adj[v].pb(mp(i, u)); 182 ee[i].u = u, ee[i].v = v; 183 } 184 find_bcc(n); 185 int cut_cnt = 0; 186 for(int i = 0; i < n; i++) 187 if(iscut[i]) 188 { 189 cut_cnt++; 190 int u = cut_cnt+bcc_cnt; 191 for(int k = 0; k < adj[i].size(); k++) 192 { 193 int v = ebccno[adj[i][k].first]; 194 if(flag[v] != u ) 195 { 196 flag[v] = u; 197 g[v].pb(u); 198 g[u].pb(v); 199 } 200 } 201 } 202 memset(vv, 0, sizeof(vv)); 203 cnt = 0; 204 for(int i = 1; i <= bcc_cnt+cut_cnt; i++) 205 if(!vv[i]) 206 ST(i, 0, 0); 207 int q; 208 Init();//记得初始化啊 。。。。。。。。 209 for(int i = scanf("%d", &q); i <= q; i++) 210 { 211 int s, t; 212 scanf("%d%d", &s, &t); 213 s = ebccno[s], t = ebccno[t]; 214 int ss , tt; 215 ss = min(R[s], R[t]); 216 tt = max(R[s], R[t]); 217 int lca = RMQ(ss, tt); 218 lca = E[lca]; 219 int ans = dis[s] + dis[t] - 2 * dis[lca] + (lca > bcc_cnt); 220 printf("%d\n", ans); 221 } 222 } 223 return 0; 224 }
两者时间上差不多,而且ST算法需要初始化,更容易出错