Java solution explained using array
class Solution {\n\n    int arr[];\n    Random rand;\n    int cumulativeSum;\n    int rectangles[][];\n    public Solution(int[][] rects) {\n        rectangles 
class Solution {\n\n    int arr[];\n    Random rand;\n    int cumulativeSum;\n    int rectangles[][];\n    public Solution(int[][] rects) {\n        rectangles = rects;\n        rand = new Random();\n        int n = rects.length;\n        arr = new int[n];\n        cumulativeSum = 0;\n        for(int i=0;i<n;i++) {\n            int each[] = rects[i];\n\t\t\t// finding the number of points within this rectangle \n            int curPoints = (each[2] - each[0] + 1) * (each[3] - each[1] + 1);\n\t\t\t\n\t\t\t// It will be easier to select index if we maintain cumulative probabilities.\n\t\t\t// Because binary search works on sorted array. \n\t\t\t// If we maintain only curPoints, then we need to sort that array. Then it takes a lot of time.\n\t\t\t// If we maintain cumulative curPoints then it will always be in sorted manner and then difference between two adjacent curPoints is more, then then there are more chances to get that index.\n            cumulativeSum += curPoints;\n            arr[i] = cumulativeSum;\n        }\n    }\n    \n    public int[] pick() {\n\t\n\t\t// Finding random integer between [1, cumulativeSum]\n        int randSum = rand.nextInt(cumulativeSum + 1);\n        \n        int l = 0;\n        int r = arr.length;\n        \n\t\t// Picking the upper bound\n        while(l < r) {\n            int m = l + (r-l)/2;\n            \n            if(arr[m] > randSum)\n                r = m;\n            else\n                l = m+1;\n        }\n        \n        int pickedRect[] = l < arr.length ? rectangles[l]: rectangles[l-1];\n        \n        int bl = pickedRect[0];\n        int br = pickedRect[1];\n        int tl = pickedRect[2];\n        int tr = pickedRect[3];\n        \n\t\t// Picking the random point within the chosen rectangle\n\t\t// We need to choose a point , let it be (x, y)\n\t\t// x can run from pickedRect[0] to pickedRect[2]\n\t\t// y can run from pickedRect[1] to pickedRect[3]\n        return new int[]{bl + rand.nextInt(tl-bl+1), br + rand.nextInt(tr-br+1)};\n        \n    }\n}\n\n/**\n * Your Solution object will be instantiated and called as such:\n * Solution obj = new Solution(rects);\n * int[] param_1 = obj.pick();\n */
['Binary Tree']