Binary Lifting Algorithm

I have run into 2 different problems that can be solved using binary lifting. Then there is second thread's tree basics youtube video that talks about this technique with some practice problems. So this blog collects problems that can be solved using this technique. I am not gonna dive into each problem in detail. Each problem already has a well explained editorial. 

 

 

[LeetCode 1483] Kth Ancestor of a Tree Node

[Codeforces Robots on a Grid]

Lowest Common Ancestor

Query to find the maximum and minimum weight between two nodes in a given tree using LCA

=================================================================================================================================

Maximize Value of Function in a Ball Passing Game

There are N nodes, each node u has 1 sinlge out-going edge to another node v, it is possible that u == v. 

Given a step K and a starting node u, F(u) is the sum of all node ids after jumping K steps, the starting node id is considered part of the F(u) before making any jump.

Get the max value of F(u) over all possible starting nodes. 

 

If we solve this problem using a naive approach, the runtime is O(N * K), if K is large, it will be too slow. 

A better approach is to use binary lifting. 

 

class Solution {
    private int[][] forward;
    private long[][] dp;
    public long getMaxFunctionValue(List<Integer> receiver, long k) {
        int n = receiver.size();
        int LEVEL = (int)Math.ceil(Math.log(k) / Math.log(2));
        forward = new int[n][LEVEL + 1];
        dp = new long[n][LEVEL + 1];

        for(int i = 0; i < n; i++) {
            forward[i][0] = receiver.get(i);
            dp[i][0] = receiver.get(i);
        }
        for(int j = 1; j <= LEVEL; j++) {
            for(int i = 0; i < n; i++) {
                forward[i][j] = forward[forward[i][j - 1]][j - 1];
                dp[i][j] = dp[i][j - 1] + dp[forward[i][j - 1]][j - 1];
            }
        }
        long ans = 0;
        for(int i = 0; i < n; i++) {
            long sum = i;
            int currNode = i;
            //compute f(i) using the binary lifting computation results
            for(int j = 0; j <= LEVEL; j++) {
                if((k & (1l << j)) != 0) {
                    sum += dp[currNode][j];
                    currNode = forward[currNode][j];
                }
            }
            ans = Math.max(ans, sum); 
        }
        return ans;
    }
}

 

 

During contest, I tried to use the following idea to solve this problem but the implementation is a lot more involving so I ran out of time, but I think the idea is correct.

Given the constraints, we know that for any given node, if we follow the edges, we will eventually run inside a cycle. so the general case is that we deal with multiple cycles with possible tails. 

If we know the length of each cycle and the tail's length, we can pick a node in the cycle, compute the number of times that K jumps go through the cycle and the remaining jumps that are < cycle length. Similarly we can pick a node in the tail, comptue the number of jumps needed to get to the first node that is inside a cycle, then perform a similar math logic. For all the rest of nodes in the same cycle / tail, we can leverage the technique that is similar to sliding window. 

 

This idea is correct but is a lot more difficult to implement compared with the binary lifting solution. 

 

 

 

 

posted @ 2020-08-25 11:53  Review->Improve  阅读(236)  评论(0编辑  收藏  举报