LCA + two points (a good question, a difficult thinking and a programming skill, but it is not too difficult to write, a good question !)
For more information, see
The distance between two points is the distance between two points * 2.
1. generally, it is easy to think that a State can be regarded as a vertex, so the transition between States can be regarded as the edge connecting between points, and it should be a undirected edge, two statuses can be converted. However, it is not enough to think of it here. If we can think of it as a binary tree, it is perfect. It should be said that it is an infinitely deep Binary Tree, and each node has two sons, not only one
Why is it a binary tree? for each State, there must be only three or two transfer possibilities.
For a State, we sort the three vertices in order, x <y <z
If y-x = z-y, there are only two types of hops, that is, y jumps to both sides and two new statuses can be generated.
If y-x <z-y, there are three types of hops: y to both sides, and x to y and z.
If y-x> z-y, there are three types of hops: y jumps to both sides, and z jumps to y and x respectively.
It can be found that the above description already contains all possible states. Think about the graph. The degree of each vertex can only be 2 or 3, not 0 or 1, or greater than 3, that is, a binary tree!
The degree of all vertices is 3 and the degree of root is 2.
For y to jump to both sides, any State can be done, it is equivalent to a binary tree, each node has two sons. The latter two States can also jump to the middle, which is like every point in the binary tree can move toward the parent (except Root !)
It is straightforward to come to some conclusions.
1. for 1st class states, that is, y-x = z-y, equivalent to the root of a binary tree
2. For status 2 and 3, it is equivalent to a non-root node of a binary tree.
3. For the new state that y jumps to both sides and generates, it is seen that the node of the binary tree moves to its two sons.
Here, the problem state is, get two states, corresponding to the two points on the binary tree, find the distance between the two points, that is, the LCA
1. first, we can easily think that the entire graph may be not connected, that is, more than one binary tree. If the start and end statuses are not in the same tree, that is, the root state is different, then they are not mutually accessible, and NO is output.
2. If the two points are on a tree, they will certainly make them reach each other and output YES. The rest is how to find the LCA.
1. How to judge whether two points are not in a tree? The method is very simple: Find the roots of the two States and check whether they are the same.
An obvious method is to simulate the process, that is, to return to the root step from the current State until the y-x = z-y state is met. However, we can see that, the simulation time is O (n) and has timed out.
It seems like 1 2 10 ^ 8. The data returned to the root of the tree has timed out, so we cannot simulate it step by step. We should use a mathematical method.
Use several examples to illustrate the problem
1 3 9 ---- "3 5 9 -----" 5 7 9, return to the root of the tree
1 3 10 -----, 3 5 ------, 5 7 10 ----------, 7 9 10
7 9 10 --------- "7 8 9, return to the root of the tree
Case 1: 1 3 9 ---- "3 5 9. In fact, 1 jumped to the position of 5 and took 1 step, however, we can see that 1 and 3 are jumped to 3 and 5 at the same time, and 1 step is used,
So from 1 3 9 to 5 7 9, it can be seen that 1 jumps to 5, 3 to 7, and 2 cells are jumped each time and 2 steps are taken.
Case 2: 1 3 9 ----- "7 9 10" can be seen as 1 jump to 7, 3 jump to 9, 2 cells each time, 3 times, and then from 7 9 10 ------, 7 8 9
This revelation allows us to regard the Skip process as one part. Each part can be calculated using mathematics and a few steps are taken to figure out the subsequent State.
Let's look at case 1: len = 3-1 = 2 _ len = 9-3 = 6 6/3-1 = 2, so it takes two steps from 1 3 9 to 5 7 9.
Let's look at case 2: len = 3-1 = 2 _ len = 10-3-7 7/3 = 3, so it takes three steps from 1 3 10 to 7 9 10.
The formula above actually makes a judgment, that is, whether there is division. If the Division operator is reduced by 1, no division operator does not need to be reduced by 1.
Therefore, we can use this technique to avoid judging c (number of steps) = (_ len-1)/len, so we can avoid judgment. This formula is easy to think about.
(The above part is a programming technique that avoids discussion and does not affect the problem solving. The same method is used for case 2, 10 to 9)
In this way, we solve another problem, that is, how to quickly calculate the root of a State and know how many steps are used. This is actually the depth of the state in the tree (the root depth is 0)
This method is similar )"
Next, how to find the LCA
First, we saved the depth of the two States in the tree when looking for the starting and ending States. First, we made a process to move the deeper vertices in the two vertices up, until the depth of the two points is the same, this is to prepare for the second point. But remember, the number of steps to be adjusted is the answer.
The next two points are in the same depth, so the two points are to find the depth of the LCA! (We do not need to know its status even though we do not directly look for the LCA status)
If the depth of the current two points is dep and the depth of the LCA is d, the distance between the two points is 2 * (dep-d). Do not forget the previous adjustments, therefore, the answer should be 2 * (dep-d) + adjusted steps
How can we achieve binary classification?
The depth of the two points is dep and the root depth is 0. Therefore, the depth of the LCA must be within [0, dep] (double closed interval). Then we will give two answers.
Split a result d, then the depth difference delta = dep-d, and then look at the starting status to go up the delta step, and from the ending status to go up the delta step, whether the two new States are the same
If they are different, it means that we haven't gone through the LCA, that is to say, below the LCA, so the delta should be bigger, and d should be smaller (the LCA should be higher, and the depth should be smaller)
So the second part goes to the higher position.
If the two new States are the same, it indicates that the new State may be the ancestor of the LCA or the LCA (because from the beginning of the LCA, they all share the same ancestor, only the LCA is the latest one), so delta should be smaller, and d should be larger (the LCA may be lower and deeper), so the second point should be lower.
In this way, the problem of code implementation is solved.
We calculated the delta, and walked up the delta step from the current state and got a new state. What should we do? Similarly, we can simulate and step by step, but the results will time out like we mentioned earlier. Because there are too many iterations, this problem can be quickly solved by mathematical methods, the method is the same as the above-mentioned "moving and Division (subtraction)", but it is an inverse process. I will not go into details here. Let's look at the updata () function of the Code.
Inline void SORT (State & a): sorts three vertices in a State a to ensure that x <y <z
State Root (State & a): for a given State a, calculate its Root State and return it. In addition, calculate the depth of a and update it in.
Void updata (State & a, ll delta): Given a status a and the number of steps going up delta, find the new status generated after a goes up the delta step, and return
# Include <iostream> # include <cstdio> # include <cstring> # include <vector> # include <algorithm> using namespace std; # define ll _ int64struct State {ll x, y, z; ll dep;}; State S, T; inline bool cmp_state (State a, State B) {if (. x = B. x &. y = B. y &. z = B. z) return true; return false;} inline ll Abs (ll x) {return x> 0LL? X:-x;} inline void SORT (State & a) {if (. y <. x) swap (. x,. y); if (. z <. x) swap (. x,. z); if (. y>. z) swap (. y,. z);} State Root (State & a) {State tmp = a; tmp. dep = 0; ll dep = 0; while (Abs (tmp. x-tmp. y )! = Abs (tmp. y-tmp. z) {ll len = Abs (tmp. x-tmp. y); ll _ len = Abs (tmp. y-tmp. z); if (_ len> len) {ll c = (_ len-1)/len; // cleverly, avoid judging dep + = c; tmp. y + = c * len; tmp. x + = c * len;} else {ll c = (len-1)/_ len; dep + = c; tmp. y-= c * _ len; tmp. z-= c * _ len;} // printf ("% d \ n", tmp. x, tmp. y, tmp. z);}. dep = dep; return tmp;} void updata (State & a, ll delta) {ll count = 0; while (count <Delta) {ll len = Abs (. x-. y); ll _ len = Abs (. y-. z); ll k = Abs (count-delta); // The number of remaining steps if (len <_ len) {ll c = (_ len-1) /len; // The number of steps to be moved ll Min = min (k, c);. x + = Min * len;. y + = Min * len; count + = Min; if (Min = k) break;} else {ll c = (len-1)/_ len; ll Min = min (k, c);. y-= Min * _ len;. z-= Min * _ len; count + = Min; if (Min = k) break;}. dep-= delta;} ll solv E () {State tS, tT; ll low = 0, high = S. dep; while (low <= high) {ll mid = (low + high)> 1; ll delta = S. dep-mid; tS = S; tT = T; updata (tS, delta); // SORT (tS); updata (tT, delta); // SORT (tT ); if (! Cmp_state (tS, tT) high = mid-1; else low = mid + 1;} return 2 * (S. dep-high);} int main () {// while (cin> S. x> S. y> S. z> T. x> T. y> T. z) while (scanf ("% I64d % I64d % I64d", & S. x, & S. y, & S. z )! = EOF) {scanf ("% I64d % I64d % I64d", & T. x, & T. y, & T. z); S. dep = T. dep = 0; SORT (S); SORT (T); State RS = Root (S); State RT = Root (T ); // printf ("% d \ n", RS. x, RS. y, RS. z, RS. dep); // printf ("% d \ n", RT. x, RT. y, RT. z, RT. dep); if (! Cmp_state (RS, RT) {// cout <"N0" <endl; printf ("NO \ n"); continue;} ll tflat = Abs (S. dep-T. dep); // record if (S. dep> T. dep) updata (S, S. dep-T. dep); else updata (T, T. dep-S. dep); // printf ("% d \ n", S. x, S. y, S. z, S. dep); // printf ("% d \ n", T. x, T. y, T. z, T. dep); ll res = solve (); // cout <"YES" <endl; // cout <tmip + res <endl; printf ("YES \ n"); printf ("% I64d \ n", res + tmip);} return 0 ;}