Turn from cold incense: Ghost (the question is where you can't stay ). First of all: http://acm.hdu.edu.cn/showproblem.php? PID = 1, 4338It's easy to scale the ring to a point, just do it. However, when I draw another picture, I will find some situations very troublesome. For example, I suddenly think this is a pain point. The one in the middle is the connected set .. Then, the problem can be effectively solved by using the dual-connectivity component and cut point graph creation. Example:
// After make_map creates a cut point and a point pair of connections:
The red color corresponds to the cut point, and the black color refers to the point-connected component. When we calculate (), we can view the set in the tree where is located, respectively, find all sum = 2 + 1 + 3 + 1 + 3 + 3 + 1 + 2 = 13 in the path. Because the cut point is calculated repeatedly, the number of computations is the number of tree edges, len = 6, ANS = sum-len = 7. The answer is that there may be seven points. Then there is how to implement the above problems.
For example, the shortest distance of is LCA (), and the result is that the length of all the paths from the root to a certain point is defined as sson [I]. NB [I] is the number of elements in the tree node in the set sum = sson [1] + sson [2]-2 * sson [3] + NB [3] Len = deep [1] + deep [2]-2 * deep [3, the problem turned to the problem of finding the LCA... by the way, record the information used above. I have been writing code for a long time, which is quite frustrating... For details, refer to the Code: use C ++ to deliver data, otherwise the stack will overflow.
# Define sz100005 struct node {int S, T, NXT;} e [SZ * 10]; int HD [SZ], CNT; void insert (int s, int T) {e [CNT]. S = s; E [CNT]. T = T; E [CNT]. NXT = HD [s]; HD [s] = CNT ++;} // The Tarjan cut-Point Template. By the way, obtain the point-connected component. // If the stack overflow occurs, add // # pragma comment (linker, "/Stack: 102400000,102400000") int dfn [SZ], low [SZ], iscut [SZ] at the beginning of the Code, sta [SZ]; int deep, top, bnum, root; vector <int> block [SZ]; void Tarjan (int s, int pre) {int flag = 0; dfn [s] = low [s] = ++ dee P; STA [top ++] = s; For (INT I = HD [s]; I! =-1; I = E [I]. NXT) {int T = E [I]. t; If (t = pre &&! Flag) // determine the parent edge, and the secondary edge appears. The connection {flag = 1; continue;} else if (dfn [T] =-1) {Tarjan (t, s); low [s] = min (low [s], low [T]); If (low [T]> = dfn [s]) {If (pre =-1) Root ++; else iscut [s] = 1; int TP; do {TP = sta [-- top]; block [bnum]. pb (TP);} while (TP! = T); block [bnum]. pb (s); bnum ++ ;}} else {LOW [s] = min (low [s], dfn [T]) ;}} struct node1 {int s, t, V, NXT;} e1 [SZ * 10]; int hd1 [SZ], cnt1; void insert1 (int s, int t) {e1 [cnt1]. S = s; e1 [cnt1]. T = T; e1 [cnt1]. NXT = hd1 [s]; hd1 [s] = cnt1 ++;} int lab [SZ]; // ing int NB [SZ]; // used to specify the number of cut points in a record. Int dpmin [SZ] [20]; int dpminid [SZ] [20]; int R [SZ * 2], R [SZ * 2], lab1 [SZ * 2], sson [SZ * 2], posid [SZ * 2]; void create_dpmin (int n) {for (INT I = 1; I <= N; I ++) {dpmin [I] [0] = R [I]; dpminid [I] [0] = I;} For (Int J = 1; j <= Log (double) (n + 1)/log (2.0); j ++) for (INT I = 1; I + (1 <j) -1 <= N; I ++) if (dpmin [I] [J-1] <dpmin [I + (1 <(J-1)] [J-1]) {dpmin [I] [J] = dpmin [I] [J-1]; dpminid [I] [J] = dpminid [I] [J-1];} else {dpmin [I] [J] = dpmin [I + (1 <(J-1)] [J-1]; dpminid [I] [J] = dpminid [I + (1 <(J-1)] [J-1];} int LCA (int A, int B) {If (R [a]> r [B]) Return LCA (B, A); A = R [a]; B = R [B]; int K = (INT) (log (double) (B-A + 1)/log (2.0); Return (dpmin [a] [k] <dpmin [B-(1 <K) + 1] [k])? Dpminid [a] [k]: dpminid [B-(1 <k) + 1] [k];} void DFS (INT S, int POs, int pre, int LB, int CNT) {If (R [s] =-1) {R [s] = deep; lab1 [s] = LB ;} posid [Deep] = s; R [Deep ++] = Pos; sson [s] = CNT + NB [s]; for (INT I = hd1 [s]; I! =-1; I = e1 [I]. NXT) {If (e1 [I]. T = pre) continue; DFS (e1 [I]. t, POS + 1, S, LB, sson [s]); posid [Deep] = s; R [Deep ++] = POS ;}} void solve (int n) {// calculates the cut point and returns the double-connected rep (I, n) block [I]. clear (); memset (iscut, 0, sizeof (iscut); memset (dfn,-1, sizeof (dfn); Deep = Top = bnum = 0; rep (I, n) if (dfn [I] =-1) {root = 0; Tarjan (I,-1 ); iscut [I] = (root> 1);} memset (lab,-1, sizeof (LAB); int K = 0; rep (I, n) if (iscut [I]) {lab [I] = K; NB [k] = 1; k ++ ;} Memset (hd1,-1, sizeof (hd1); cnt1 = 0; rep (I, bnum) {rep (J, block [I]. size () {int L = block [I] [J]; If (iscut [l]) {insert1 (lab [L], k); insert1 (K, lab [l]);} else {lab [l] = K;} NB [k] = int (Block [I]. size (); k ++;} deep = 1; memset (R,-1, sizeof (R); rep (I, K) if (R [I] =-1) DFS (I, 0,-1, I, 0); create_dpmin (deep-1); int Q, S, T, u, V, FA; scanf ("% d", & Q); rep (I, q) {scanf ("% d", & S, & T ); if (S = T) // same {printf ("% d \ n", n-1); Continue;} If (lab [s] =-1 | lab [T] =-1) // when lab is-1, it indicates an isolated point, neither a cut point nor block {printf ("% d \ n", n); continue;} u = lab [s]; // maps to the previous point v = lab [T]; If (lab1 [u]! = Lab1 [v]) // judge the connectivity of the tree formed by the block, not in the same set {printf ("% d \ n", n); continue ;} fa = LCA (u, v); // return the location of the LCA after DFS in the r string. The R string is the depth fa = posid [fa] to be used by the LCA; // posid corresponds to the node int Len corresponding to the r string; len = R [R [u] + R [R [v]-2 * R [R [fa]; // path length int ans; ans = sson [u] + sson [v]-2 * sson [fa] + NB [fa]; ANS-= Len; printf ("% d \ n ", n-ans) ;}} int main () {int n, m, S, T; int CAS = 1; while (~ Scanf ("% d", & N, & M) {memset (HD,-1, sizeof (HD); CNT = 0; rep (I, m) {scanf ("% d", & S, & T); insert (S, T); insert (t, s);} printf ("case # % d: \ n ", CAS ++); solve (n); printf (" \ n ");}}
The question is to give you a starting point and an ending point. If a person wants to go from the starting point to the ending point, he cannot go through a point twice and asks him what points he cannot go through.
Obviously, it is possible to think about the points that can pass through, and then use N minus the points that can pass through to get the answer. The following discussion is based on the number of points that may pass.
It is easy to think of using dual-Unicom components, but creating a graph is really troublesome. For example, if a person wants to go from 1 to 3, the possible points are 1, 2, 3. Because 2 is a cut point, if it goes from 2 to 4, to reach 3, it must go through 2 again. Therefore, you can use the cut point and double link to create a graph.
You can use the cut point and double Unicom to build a graph adjacent to the cut point, as shown in the right figure. It can be proved that this is a tree, because if there is a ring, this ring can be scaled into a vertex, and any two points in the tree have only one path, therefore, you only need to count the total number of points in this path. However, one problem is that the cut point will be repeatedly counted, and each cut point will be calculated by the dual-connected components on the left and right of the cut point. Therefore, you only need to subtract the number of points from the number of edges on the path, for example, for 1-3, the answer is 2 + 1 + 2-2 = 3.
To quickly calculate the sum of points in a path, we need to use LCA. DP first processes the distance from each node to the root node dis [u], and the total number of nodes to the root node tsum [u]. the number of nodes contained in each node is calculated as sum [u]. the number of points in this path is ans = (tsum [u] + tsum [v]-2 * tsum [LCA (u, v)] + sum [LCA (u, v)])-(DIS [u] + dis [v]-2 * Dis [LCA (u, v)]). LCA can be converted to rmq for online query. logn is complex for each query.
Pay attention to a few small issues, and use and check the set for merging During the creation, so that you can quickly determine whether the two points are in the same connected component. In addition, you can Virtualize a Father's Day point, each edge is connected to all connected blocks, which makes DP much more convenient. During query, the point is mapped. If this point is a cut point, it must be mapped to the node corresponding to the cut point, because the cut point will be dyed into different colors in Tarjan.
There are several small trick points, which may not be connected between the start point and the end point, or may be at the same point, which requires special judgment.
The pitfall is that DP will blow up the stack, but it will be troublesome to convert the LCA to rmq without DP. You can only manually expand the stack (plus the first line), and then use C ++ to submit the stack.
# Pragma comment (linker, "/Stack: 102400000,102400000") # include <string. h> # include <stdio. h> # include <math. h >#include <algorithm> # define maxn 100005 struct edge {int U, V, N;} e1 [maxn * 4], E2 [maxn * 4]; int F1 [maxn], F2 [maxn * 2], ES1, ES2; int n, m, Q, tu, TV; void addedge1 (INT U, int V) {e1 [ES1]. U = u, e1 [ES1]. V = V, e1 [ES1]. N = F1 [u], F1 [u] = ES1 ++;} void addedge2 (int u, int v) {e2 [ES2]. U = u, E2 [ES2]. V = V, E2 [ES2]. N = F2 [u], F2 [u] = ES2 ++;} // === = int P [maxn * 2]; int find (int x) {return x = P [x]? X: P [x] = find (P [x]);} void merge (int x, int y) {P [find (x)] = find (y );} // === DP & rmq === int sum [maxn * 2], tsum [maxn * 2], DIS [maxn]; int lca_f [maxn * 4], lca_ B [maxn * 4], lca_p [maxn * 2], RID; int dminv [maxn * 4] [20], dminid [maxn * 4] [20]; void dp (int u, int F, int DD, int ToT) {// printf ("% d: % d \ n", U, DD, sum [u]); DIS [u] = DD, tsum [u] = tot + sum [u]; lca_f [++ RID] = u, lca_ B [RID] = DD, lca_p [u] = RID; For (INT I = F2 [u]; I! =-1; I = e2 [I]. n) {int v = e2 [I]. v; If (V = f) continue; DP (v, U, DD + 1, TOT + sum [u]); lca_f [++ RID] = u, lca_ B [RID] = dd ;}} void makermq () {rid = 0; DP (0,-1, 0); For (INT I = 1; I <= RID; I ++) dminv [I] [0] = lca_ B [I], dminid [I] [0] = I; int maxj = (INT) (log (RID + 1.0) /log (2.0); For (Int J = 1; j <= maxj; j ++) {int Maxi = rid + 1-(1 <j ); for (INT I = 1; I <= Maxi; I ++) {If (dminv [I] [J-1] <dminv [I + (1 <(J-1)] [J-1]) {dminv [I] [J] = dminv [I] [J-1]; dminid [I] [J] = Dminid [I] [J-1];} else {dminv [I] [J] = dminv [I + (1 <(J-1)] [J-1]; dminid [I] [J] = dminid [I + (1 <(J-1)] [J-1] ;}}} int LCA (INT X, int y) {If (lca_p [x]> lca_p [y]) STD: swap (x, y); X = lca_p [X], y = lca_p [y]; int K = (INT) (log (Y-x + 1.0)/log (2.0 )); int xx = dminv [x] [k] <dminv [Y + 1-(1 <k)] [k]? Dminid [x] [k]: dminid [Y + 1-(1 <k)] [k]; return lca_f [XX];} // === Tarjan === int dfn [maxn], low [maxn], CID [maxn], STK [maxn], Col [maxn], top, IND, CLS, TMP; int Cal [maxn * 2]; // The condition for splitting is that the root node can search for two branches or low [v]> = dfn [u], find the cut point and give the cut point number void dfs_cutpnt (int u, int F, int root) {dfn [u] = low [u] = ++ ind; int CNT = 0; int flag = 0; For (INT I = F1 [u]; I! =-1; I = e1 [I]. N) {int v = e1 [I]. V; If (V = F &&! Flag) {flag = 1; continue;} If (! Dfn [v]) {CNT ++; dfs_cutpnt (v, U, root); If (low [v] <low [u]) low [u] = low [v]; If (u = root & CNT> 1 & cid [u] = 0) CID [u] = ++ CLs, sum [CLS] = 1; else if (u! = Root & low [v]> = dfn [u] & cid [u] = 0) CID [u] = ++ CLs, sum [CLS] = 1;} else if (dfn [v] <low [u]) low [u] = dfn [v];} // locate the dual-China Unicom component and give the dual-China Unicom component number. When the dual-China Unicom component contains a cut point, a side void dfs_tarjan (int u, int F) is connected) {LOW [u] = dfn [u] = ++ ind; STK [++ top] = u; int flag = 0; For (INT I = F1 [u]; i! =-1; I = e1 [I]. N) {int v = e1 [I]. V; If (V = F &&! Flag) {flag = 1; continue;} If (! Dfn [v]) {dfs_tarjan (v, U); If (low [v] <low [u]) low [u] = low [v]; if (low [v]> = dfn [u]) {sum [++ CLS] = 1, Col [u] = CLS; do {TMP = STK [top --], col [TMP] = CLs, ++ sum [CLS]; If (CID [TMP]) {addedge2 (CID [TMP], CLS); addedge2 (CLS, CID [TMP]); merge (CID [TMP], CLS) ;}} while (TMP! = V); If (CID [u]) {addedge2 (CID [u], CLS); addedge2 (CLS, CID [u]); merge (CID [u], CLs) ;}}} else if (dfn [v] <low [u]) low [u] = dfn [v] ;}} int size; void makegraph () {// find the cut point memset (dfn, 0, sizeof dfn); memset (low, 0, sizeof low); memset (CID, 0, sizeof CID ); CLS = ind = 0; // find the double Unicom component and create the graph for (INT I = 0; I <n; I ++) dfs_cutpnt (I,-1, I ); memset (dfn, 0, sizeof dfn); memset (low, 0, sizeof low); memset (COL, 0, sizeof col); Top = ind = 0; for (INT I = 0; I <n; I ++) dfs_tarjan (I,-1); // fill the forest into a tree to facilitate DP and query memset (CAL, 0, sizeof Cal ); for (INT I = 1; I <= CLS; I ++) {If (Cal [find (I)] = 0) {Cal [find (I)] = 1; addedge2 (0, I) ;}} int main () {// freopen ("test. in "," r ", stdin); int CAS = 1; while (scanf (" % d ", & N, & M )! = EOF) {memset (F1,-1, sizeof F1); memset (F2,-1, sizeof F2); For (INT I = 0; I <= 2 * N; I ++) P [I] = I; ES1 = ES2 = 0; For (INT I = 0; I <m; I ++) {scanf ("% d", & tu, & TV); addedge1 (Tu, TV); addedge1 (TV, tu );} // convert the image makegraph () adjacent to the connection and cut points; // convert the image into rmq makermq (); printf ("case # % d: \ n ", CAS ++); scanf ("% d", & Q); While (Q --) {scanf ("% d", & tu, & TV ); // The start point and end point coincide with if (Tu = TV) printf ("% d \ n", n-1 ); else {// if it is a cut point, you must use the corresponding cut point, because the cut point will be colored differently! Tu = CID [Tu]? CID [Tu]: Col [Tu]; TV = CID [TV]? CID [TV]: Col [TV]; // If (Tu = 0 | TV = 0 | find (TU )! = Find (TV) {printf ("% d \ n", n);} else {int fa = LCA (Tu, TV ); int ans = tsum [Tu] + tsum [TV]-2 * tsum [fa] + sum [fa]; ans-= (DIS [Tu] + dis [TV]-2 * Dis [fa]); printf ("% d \ n", N-ans );}}} printf ("\ n");} return 0 ;}