### halin.george's blog

By halin.george, history, 4 years ago,  Tutorial of Codeforces Round #381 (Div. 1) Tutorial of Codeforces Round #381 (Div. 2) Comments (41)
 » 4 years ago, # | ← Rev. 2 →   Could someone please look at my code for 739B? I was getting WA on pretest 15 and am not sure why...I store the 2^k ancestors and the distance to them in bparent[][] and bdist[][]. I then binary search for each node that controls the node that I am on and store the start and end segments in event[]. The function solve() dfs's through the tree, keeping track of how many nodes each node controls.Thanks!
 » For problem D, how do we store the ancestors of all nodes in O(n)?
•  » » 4 years ago, # ^ | ← Rev. 2 →   You only store the (2^k)th ancestors of a node -> O(n*log n)
 » Can someone explain the approach for the problem 'Alyona and Tree'
•  » » 4 years ago, # ^ | ← Rev. 3 →   This is the binary search method that may not be the easiest, I recommend checking out zawini54's comment too!A few observations could be made: dist(v, u) = dist(root, u) - dist(root, v) for any vertex v, and its ancestors a1, a2, ..., ai,a1 being the furtherest ancestor (root of the tree) and ai the closest (immediate parent vertex),we can see that dist(root, a1) < dist(root, a2) < ... < dist(root, ai) < dist(root, v), a sorted sequence that is binary searchable. for each vertex v, we want to find the number of vertices u it controls, i.e.:dist(v, u) ≤ value(u) dist(root, u) - dist(root, v) ≤ value(u) dist(root, u) - value(u) ≤ dist(root, v) with #2 and #3 in mind, let's try to think of this problem in another way: for each vertex u, which vertices v could control u?
•  » » » Ok, for each vertex u, I can find how many ancestor controls it, but how do I use this information to find out the reverse?
•  » » » » this can be maintained using segment tree on the path from root to current vertex
•  » » » Let u is controlled by x vertices. Then the immediate x parents of u could control this vertex u.But a simple approach in getting the answer requires O(n^2) which would fail on the time limit. Can you suggest a better approach?
•  » » » » Consider the array, A = [6, 1, 6, 9, 3]We can compute an array of differences between the neighbouring two elements, a difference array, D = [6,  - 5, 5, 3,  - 6], Note how we can reconstruct the array A from its difference array D, A = DA = D + DA = D + D + DA = D + D + D + DA = D + D + D + D + D If we can somehow first construct a difference "array" D for this problem, then we can reconstruct the answer "array" A from it.
•  » » » » » Nice thought.Thanks a lot.
•  » » » » » Sorry, I still do not get it. How do you get this difference array?
 » Actually there's another solution that doesn't use binary lifting, but the merging sets technique. I think it's easier, because at first I thought of doing something with binary lifting but wasn't able to come up with anything. Check it out: 22490570
•  » » 4 years ago, # ^ | ← Rev. 3 →   Nice approach, btw are you making reference to the technique disscused at this post?
•  » » I considered merging set approach during contest, but couldn't find a way to count the number of elements <= d in O(logn) using std::set, now I know it's unnecesary for this problem after reading you code.However, if the condition change to that v controls u if dist(v, u) <= a(v) (instead of a(u)), it seems we must have a way to count the number of elements <= d in O(logn) using merging set approach, and std::set doesn't satisfy this.
•  » » » Actually, I don't think my approach works with the harder version of the problem, since it relies on that fact that d(v) is monotonically increasing as you go down the tree. I think there should be a solution involving segment tree and coordinate compression, but I haven't thought about it that much. Please feel free to correct me on anything.
•  » » » But Ordered Statistics Tree does. Can't we use it instead of sets?
•  » » An explanation please?
•  » » » 4 years ago, # ^ | ← Rev. 2 →
•  » » » » This is Amazing. Thanks a lot I'm definitely gonna remember this after-before strategy! I had a few situations where I needed this and this was pretty neat.
•  » » Hi,your approach looks amazing, I just learned binary lifting through this problem and now you propose another way of doing the problem... Where did you learn this technique from, I want to learn this too,is there some blog post associated with it , or some source where I can learn the merging set technique,because I cant understand your solution , can you also explain it just a little..?Thanks a ton!
•  » » »
•  » » » For anyone looking for a binary lifting solution: here it is
•  » » » » Explanation to the binary lifting solution:The base idea can be seen here. We just don't use the binary search over the ancestors of a node. We create the parent's DP, that is required to do binary lifting. I saw this video to understand binary lifting. You create an 2D matrix with dims: DP[N][HEIGHT], where DP[i][j] represents the parent of $i^{th}$ node at height $2^j$ from $i$. DP[i] is simply the direct parent of the node, already given in the question. For the others, use this: f(j,1,21) f(i,0,n) parDP[i][j] = parDP[parDP[i][j-1]][j-1] ; Where j is the height, and i is the node. If you're confused, watch the video. Now, we remove the binary search part, and instead do the search using the parent DP matrix we created. This can be done using: int s = node ; for(int d=20;d>=0;d--) { if(dist[node]-dist[parDP[s][d]]<=a[node]) { s = parDP[s][d] ; } } This is what I stole from yaksha. Thenks. What does it mean tho?It finds the farthermost parent of s, that satisfies the condition. Let's name it $\phi$. But we're iterating through the powers of 2. That is, it is possible that a parent at an height of $2^j$ from $s$, might satisfy the condition, but we didn't see $2^{j+1}-2^{j}$ elements between the two parents.So, we'll have to iterate through the parents of $\phi$. But do we have to start again? No. We know that $2^{j+1}$th parent didn't satisfy, whereas $2^j$ did. So, we have a gap of $2^{j+1}-2^j = 2^j$ elements. So, we look into the $j^{th}$ parent of $\phi$ this time. This gap closes as we progress towards d=0.Everything else is pretty much the same.Here is my submission, made from multiple code stealing activities.
•  » » » » » Hey, thanks a lot! your comment helped to finally understand
•  » » 10 months ago, # ^ | ← Rev. 2 →   Beautiful solution!This question just keeps on giving :>So explanation on the DSU on tree method to solve this problem (Alyona And Tree):There's a basic HLD (heavy light decomposition) concept of light child and heavy child in a tree for each node.So, consider you have a node $N$, which has $\alpha$ children, $C_1,C_2,C_3,...,C_{\alpha}$. Now, the child, which has the maximum size of it's subtree, is the one which is called the big child or the heavy child. Every other child is called a light child. How is this concept useful?So, for a node, consider, you need to perform some query that needs information from the whole tree, then in that case, if you do a brute force operation, then you'll get a $O(n^2)$ time complexity. What we can do here, is store the information of the big child while the traversal is done, and for the rest of the children, we do whatever we did in the brute force method.How does that help us?Basically we're not going into the big child, but are going into the light children. Consider this, if $x=tree[lightchild].size()$ and $y=tree[bigchild].size()$. So, $y > x$, obviously. So, if I merge the subtree of the lightchild into the subtree of the bigChild, then it's size: $y+x > x+x = 2\times x$. That is, each merge operation will, at least, double the size of the bigchild subtree. So, we can do this doubling operation only until the total number of elements ($=n$) is reached. That is, $log(n)$ times.And since we have $n$ nodes in total, the total time complexity is $O(n log n)$.You can learn more about DSU on graphs, here and here.Steps for the algorithm: For a node, find the bigChild. DFS through the lightChilds, and do not remember their results DFS through the bigChild, and remember it's result Add the result of the current node, if possible. Add the values of the subtrees of the lightChilds. At this point, we have the result for the node Remove the values of the lightChilds if the current node is a light child, else do not delete them This is the procedure, I understood from the tutorial.Now let's try to analyze szawinis' solution. Here we are not keeping results in some variable array or something, therefore there is no removal of values at the end of the DFS. That is, we can keep the subtree information intact, while traversing the tree. So priority queue pq stores the $\text{distance from root}-a[v]$ value for the nodes that satisfy the condition. That is for the node node, pq[node] will have the mentioned difference for the nodes which satisfy the condition (d[child]-d[node]<=a[child]). In the big for loop, if we see a light child, we push all it's values into the current node's pq. Whereas, if we see a potential bigChild, we push all the elements of the current node into the bigChild's pq and then point to the bigChild's pq as the current node's pq.The point is, not to transfer the elements of the big child (which actually makes the algorithm run in O(nlog n)). Then we disregard the elements which do not satisfy the condition. If you think that's a problem, then think how many elements in total can you remove? So yeah this can, at max n elements, because only the elements that satisfy the condition for the current node, are percolated up as potential candidates.At this point, you can take the value of pq[node].size() as the answer. And then add the node itself in it's priority queue.I hope this helps.
 » Can someone please elaborate the binary lifting method for problem D?
•  » » My Code 22652723easy to understand
•  » » » Instead of binary lifting, I think you're using binary search in here.
•  » » » 10 months ago, # ^ | ← Rev. 3 →   For everyone trying to understand Sukeesh's solution, here is an explanation:Basic what we knows: $dist(u,v) = dist(root,v)-dist(root,u)$. We're given the condition: $dist(u,v) \leq a_i$, which can be written now as $dist(root,v)-dist(root,u) \leq a_i$ (where $u$ is an ancestor of $v$). If you're looking at vertex $v$, then it's ancestors' distances from the root, will be in strictly increasing order, starting from the root itself. That is, if $a_1,a_2,a_3,...,a_i$ are the ancestors of $v$, where $a_1$ is the root, and $a_i$ is the parent of $v$, then the distance of this series of nodes, from the root, will be in strictly increasing order. Thus we can do a binary search on them. So let's see the algorithm. We're doing a DFS here.Consider we're at the vertex $v$, and we have the information of it's ancestors saved in an vector $arr$. We're saving the distance of a node from the root in the array $d$, while we're going down while the DFS. So while we're at $v$, we have the distance of it's ancestors from the root already saved in $d$. Great.Now we look for the first ancestor $a$ which doesn't satisfy the condition: $dist(root,v)-dist(root,a) \leq v_i$ $dist(root,v)-v_i \leq dist(root,a)$We can calculate the LHS of this formula for our $v$ boi, and then we can search for this value in $arr$. Let's say this value's index is $hi$. So, bringing partial sums in here fam.This part is good. So what do we have here? We can say that all ancestors of $v$ after $hi$ (including $hi$) till the parent of $v$ satisfy the condition, right?We're saving the partial sums in an array dp.So as done in partial sums, we do dp[par[v]]++ and dp[par[arr[hi]]--. You'll understand this is you know about partial sums. We increase the starting of a segment, and decrease after the end of it. Now we carry on to our DFS work.We do all this,and do complete our DFS from the root.Now we can compute the answer of each node, by using the partial sums we built during the first DFS (oh no, there's no second DFS, yet). So, we calculate the answer for each node, in the same way, we created the dp array(i.e. going through a DFS). So we calculate the dp value for the children first, and then use it to calculate the value of the parent, by adding the children dp values in the parent dp value. The function go is used to do that. void go(ll v){ for ( ll j = 0 ; j < adj[v].sz ; j ++ ){ go(adj[v][j].F); dp[v] += dp[adj[v][j].F]; } } Why is this working you ask? Consider a positive value is encountered. This means that this is a starting point for a segment of nodes which have some node $v$ for which the needed condition is satisfied. Thus we increase our dp value. If a negative value is encountered, we know that some segment has ended, and we decrease our dp value.Hope this helps someone.
 » in Div2CI can't understand why not to fill our resulted array with zeroes and printing answer as 1? is there any restriction about our resulted array, that must contain different numbers?
•  » » You want to maximize the minimum mux so if u fill the whole array with zeroes the answer will be 1 but u can fill it from 0 to the length of the array so the closest non-negative integer can be the maximum which is the length of the array.
 » In 739E — Gosha is hunting, The editorial writes "Not hard to prove that in group Y we should throw Poke Balls to Pokemons with greatest u - p." I think that we want to maximize PokeBalls probability when we throw PokeBalls. So shouldn't we throw pokeballs to pokemons with greatest p-u?
•  » » 9 months ago, # ^ | ← Rev. 2 →   That is not correct. Let me clarify a part of the editorial's proof for archival reasons. Assume that the pokemons have been sorted in descending order of $u_i$, therefore $u_0 >= u_1 >= u_2 >= .... u_{n-1}$. Now, let $i$ be the index of the last pokemon to be thrown an ultraball. Claim: For all pokemon in $[0, ... i - 1]$, we throw a ball at them (or perhaps two). Proof: Assume that there was a pokemon, say $x$, where $0 <= x < i$, and we don't throw a ball at $x$. But note that we do throw a ultraball at $i$. What is the total change if we throw that ultraball at $x$ instead?Case 1: We do not also throw a pokeball at $i$: — Loss in not throwing the ultraball at $i$ = $u_i$ — Gain in throwing the ultraball at $x$ = $u_x$.Since $u_x >= u_i$, we can throw the ultraball at $x$ and not be worse. Case 2: We do also throw a pokeball at $i$. — Loss in not throwing the ultraball at $i$ = $(u_i + p_i - p_{i}u_{i} - p_i) = u_i(1-p_i)$ — Gain in throwing the ultraball at $x$ = $u_x$.Since $u_x >= u_i >= u_i(1-p_i)$, we can throw the ultraball at $x$ and not be worse. Hence Proved
•  » » » 5 weeks ago, # ^ | ← Rev. 3 →   Can you explain the Loss in case 2 proofbycontradiction? Does it mean that (ui + pi) -> either ultraball catches the pokemon or pokeball catches it. and (uipi + pi) -> either both types of balls catches pokemon or pokeball catches it.therefore (ui + pi) — (uipi + pi) -> ultraball catches the pokemon but pokeball does not.
•  » » Yeah, I also think so
 » In Div1-A or Div2-C Why not to just fill the whole array with the maximum available value which is 10^9-1 and the maximum minimum mex becomes 10^9 ?You didn't mention anything like : the array(or subarray) elements need to be unique !What am I getting wrong here ?
•  » » "The mex of a set S is a minimum possible non-negative integer that is not in S."if you fill array with max value your ans will be 0
•  » » » Oooops , yes thanks.
 » 3 years ago, # | ← Rev. 2 →   import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public String get_SHA_512_SecurePassword(String passwordToHash, String salt){String generatedPassword = null; try { MessageDigest md = MessageDigest.getInstance("SHA-512"); md.update(salt.getBytes("UTF-8")); byte[] bytes = md.digest(passwordToHash.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for(int i=0; i< bytes.length ;i++){ sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); } generatedPassword = sb.toString(); } catch (NoSuchAlgorithmException e){ e.printStackTrace(); } return generatedPassword;}
 » Why does my code fail at test 9?It takes 45 to get from 80 to 25, and 45 is greater than 25http://codeforces.com/contest/739/submission/43924000
 » Can anybody please tell me what data structure have people used to solve 739C (Alyona and Towers)?