RainX_69

Amazon OA question related to LCA( binary lifting)

Dec 23rd, 2022 (edited)
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.08 KB | Source Code | 0 0
  1.                                                         AMAZON ONLINE ASSESSMENT
  2. /*
  3.  
  4. You are given the following:-
  5.  
  6. A tree consisting of N nodes, where every node holds either a zero or one value. You are given u and v and a string S is generated as a binary string which represents the path between u and v. You are also given a vector A representing the value of ith(1-based) node.
  7.  
  8. A GOOD string is a string where the count of "01" substring is equal to the count of "10" substring. A operation consists of flipping the bit, i.e. 1 becomes 0 and vice versa.
  9.  
  10. TASK-
  11. Determine the minimum number of operations required to convert string S into a GOOD string. You are given Q queries of the form
  12. [u , v]. Determine result for each
  13.  
  14. Example
  15.  
  16. N=5
  17. Edges = [(1,2),(2,3),(3,4),(4,5)]
  18. A = [0,1,0,1,1]
  19.  
  20. Query 1 is given as 1 5 denoting nodes u and v respectively. The simple path between node 1 and node 5 is 1-2-3-4-5. String S generated is 01011. You change the last value in the string to 0. String S becomes 01010. In the new string formed, both 01 and 10 occur 2 times which is equal. 1 operation is required to convert string S into a GOOD string, and therefore, the answer is 1.
  21.  
  22. Query 2 is given as 1 3 denoting nodes u and v respectively. The simple path between node 1 and node 3 is 1-2-3. String S generated is 010. In this string, both 01 and 10 occur an equal number of times. 0 operation required to convert string S into a GOOD string, and therefore, the answer is 0.
  23.  
  24. Constraints- N = 2 ≤ N ≤ 2 * 10^5
  25.              Q = 2 ≤ Q ≤ 2 * 10^5
  26.  
  27. Complete the given function having parameters, edges, N, A, Q
  28. */
  29.  
  30. /*--------------------------------------------------------------------------------------------------------------------------------*/
  31.                                                                     THOUGHT PROCESS
  32.                                                                    
  33. This is really a nice question. I believe its a combination of two different problems
  34.  
  35. Problem 1:-
  36. How will you efficiently find path between u->v because traditional BFS/DFS would surely result in TLE for that ridiculous          constraint?
  37.    
  38. ANSWER-> Use binary lifting to find LCA of u and v first. Precomputation takes n*logn. But after that you will be able to find LCA in logn time. After finding LCA, your path string is reverse(LCA->u)+LCA->v. This is a lot better than just doing DFS from u to v, as DFS will take N time, while this method will just take O(h) time where h is the height of LCA from leaf node
  39.  
  40. Problem 2:-
  41. How are you finding the minimum operation require to make GOOD string?
  42.    
  43. ANSWER-> Actually this is where we do not need any time!! Yes, the TC is O(1). All you need to do is check first and last character, if both of them are different, return 1 , else 0. It is basically a simple observation. So you literally did this in O(1) time. Don't believe me, here are some examples, please check the first and last character as I said,
  44. 1100001 = 0
  45. 1010101 = 0
  46. 1000001 = 0
  47. 0110010 = 0
  48. 1010100 = 1
  49. 0110101 = 1
  50.  
  51. SO BASICALLY THIS QUESTION WAS TESTING YOUR KNOWLEDGE OF LCA AND HOW EFFICIENTLY YOU CAN DO IT!!!
  52.  
  53. TIME COMPLEXITY-
  54. N * logN to precompute.
  55. Q * max( logN, H ) where H is the max height of tree, incase of linear tree.
  56.  
  57.  
  58. => CRAZY=> Now, GIVE IT A GOOD THOUGHT. Do you think we even need the path when all we check if the last and first character of the path string..HAHAHA..No, just check A[u]!=A[v] then 1 or 0. So code complexity becomes O(Q). Lmao!!!! Anyways I would still advise you to go through the code below to understand this idea of LCA used in path finding. Might be useful somewhere in the future...
  59.    
  60. /*--------------------------------------------------------------------------------------------------------------------------------*/
  61.  
  62. CODE BELOW-
  63.  
  64. #include <bits/stdc++.h>
  65. using namespace std;
  66.  
  67. int dp[200005][20];
  68. vector<int> parent;
  69. vector<int> height;
  70. vector<int> adj[200005];
  71. vector<char> values;
  72.  
  73.  
  74. void initialize(int n, vector<vector<int>> &edges){
  75.     parent.resize(n+1);
  76.     height.resize(n+1,0);
  77.     for(auto edge: edges){
  78.         adj[edge[0]].push_back(edge[1]);
  79.         adj[edge[1]].push_back(edge[0]);
  80.     }
  81. }
  82.  
  83.  
  84. void dfs(int node, int par, int d){
  85.     parent[node]=par;  
  86.     height[node]=d;
  87.     for(auto nei: adj[node]){
  88.         if(nei!=par){
  89.             dfs(nei,node,d+1);
  90.         }
  91.     }
  92. }
  93.  
  94. void pre_compute(int n){
  95.     memset(dp,-1,sizeof(dp));
  96.     for(int i=1;i<=n;i++){
  97.         dp[i][0]=parent[i];    
  98.     }
  99.     for(int i=1;i<=n;i++){
  100.         for(int jump=1;jump<20;jump++){
  101.             if(dp[i][jump-1]!=-1){
  102.                 dp[i][jump]=dp[dp[i][jump-1]][jump-1];
  103.             }
  104.         }
  105.     }
  106. }
  107.  
  108. void moveUP(int &node, int k){
  109.     for(int jump=19;jump>=0;jump--){
  110.         if(k>=pow(2,jump)){
  111.             k-=pow(2,jump);
  112.             node=dp[node][jump];
  113.         }
  114.     }  
  115. }
  116.  
  117. int LCA(int u, int v){
  118.     int heightU=height[u];
  119.     int heightV=height[v];
  120.     if(heightU>heightV){
  121.         moveUP(u,heightU-heightV);
  122.     }
  123.     if(heightV>heightU){
  124.         moveUP(v,heightV-heightU);
  125.     }
  126.     if(u==v){
  127.         return u;
  128.     }
  129.     for(int jump=19;jump>=0;jump--){
  130.         if(dp[u][jump]!=dp[v][jump]){
  131.             u=dp[u][jump];
  132.             v=dp[v][jump];
  133.         }
  134.     }  
  135.     return dp[u][0];
  136. }
  137.  
  138. string getPath(int u, int v){
  139.     int lca=LCA(u,v);
  140.     string u_lca="";
  141.     while(u!=lca){
  142.         u_lca+=values[u];
  143.         u=parent[u];
  144.     }
  145.     u_lca+=values[lca];
  146.     string v_lca="";
  147.     while(v!=lca){
  148.         v_lca+=values[v];
  149.         v=parent[v];
  150.     }
  151.     reverse(v_lca.begin(),v_lca.end());
  152.     return u_lca + v_lca;
  153. }
  154.  
  155. int convertOps(string &str){
  156.     return str[0]!=str[str.size()-1];
  157. }
  158.  
  159. int main(){
  160.     int n = 8;
  161.     vector<vector<int>> edges = {{1, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}, {3, 7}, {3, 8}};
  162.     values = {'#', '1', '0', '1', '1', '0', '1', '0', '1'};
  163.     vector<vector<int>> queries = {{1, 6}, {3, 7}, {1, 5}, {7, 8}, {4, 6}};
  164.     initialize(n,edges);
  165.     dfs(1,-1,0);
  166.     pre_compute(n);
  167.     for(auto q: queries){
  168.         string path=getPath(q[0],q[1]);
  169.         int ops=convertOps(path);
  170.         cout<<ops<<endl;
  171.     }
  172.    
  173.    
  174.    
  175.     // int n=5;
  176.     // vector<vector<int>> edges={{1,2},{2,3},{3,4},{4,5}};
  177.     // values={'#','1','0','1','0','1'};
  178.     // vector<vector<int>> queries={{1,5},{4,5},{1,5}};
  179.     // initialize(n,edges);
  180.     // dfs(1,-1,0);
  181.     // pre_compute(n);
  182.     // for(auto q: queries){
  183.     //  string path=getPath(q[0],q[1]);
  184.     //  int ops=convertOps(path);
  185.     //  cout<<ops<<endl;
  186.     // }
  187. }
  188.  
  189.  
Advertisement
Add Comment
Please, Sign In to add comment