📜  重构段树

📅  最后修改于: 2021-04-17 10:12:44             🧑  作者: Mango

我们给定2 * N – 1个整数。我们需要检查是否有可能为来自这些整数的N个不同整数的数组构造一个范围最小查询段树。如果是这样,我们必须输出段树数组。 N被赋予2的幂。
RMQ段树是一个二叉树,其中的每个节点等于其子节点的最小值。这种类型的树用于有效地找到给定范围内的元素的最小值。

Input  : 1 1 1 1 2 2 3 3 3 4 4 5 6 7 8
Output : 1 1 3 1 2 3 4 1 5 2 6 3 7 4 8
The segment tree is shown below



Input  : -381 -460 -381 95 -460 855 -242
          405 -460 982 -381 -460 95 981 855
Output : -460 -460 -381 -460 95 -381 855
         -460 -242 95 405 -381 981 855 982 
By constructing a segment tree from the output,
we can see that it a valid tree for RMQ and the
leaves are all distinct integers.

我们首先要做的是遍历给定的整数,计算每个数字的出现次数,然后按值对它们进行排序。在C++中,我们可以使用数据结构图,该图按排序顺序存储元素。
现在,我们为分段树的每个可能级别维护一个队列。我们将树的初始根(数组索引0)放入队列中以获取最大级别。然后,我们将最小的元素插入最左边的节点。然后,我们将这些节点与主树分离。分离节点时,我们将创建高度为h – 1的新树,其中h为当前节点的高度。我们可以在图2中看到这一点。我们将新树的根节点根据其高度插入适当的队列中。
我们遍历每个元素,根据该元素的出现次数获得一棵适当高度的树。如果在任何时候都不存在这样的树,则无法创建段树。

CPP
// C++ Program to Create RMQ Segment Tree
#include 
using namespace std;
 
// Returns true if it is possible to construct
// a range minimum segment tree from given array.
bool createTree(int arr[], int N)
{
    // Store the height of the final tree
    const int height = log2(N) + 1;
 
    // Container to sort and store occurrences of elements
    map multi;
 
    // Insert elements into the container
    for (int i = 0; i < 2 * N - 1; ++i)
        ++multi[arr[i]];
 
    // Used to store new subtrees created
    set Q[height];
 
    // Insert root into set
    Q[height - 1].emplace(0);
 
    // Iterate through each unique element in set
    for (map::iterator it = multi.begin();
        it != multi.end(); ++it)
    {
        // Number of occurrences is greater than height
        // Or, no subtree exists that can accomodate it
        if (it->second > height || Q[it->second - 1].empty())
            return false;
 
        // Get the appropriate subtree
        int node = *Q[it->second - 1].begin();
 
        // Delete the subtree we grabbed
        Q[it->second - 1].erase(Q[it->second - 1].begin());
 
        int level = 1;
        for (int i = node; i < 2 * N - 1;
            i = 2 * i + 1, ++level)
        {
            // Insert new subtree created into root
            if (2 * i + 2 < 2 * N - 1)
                Q[it->second - level - 1].emplace(2 * i + 2);
 
            // Insert element into array at position
            arr[i] = it->first;
        }
    }
    return true;
}
 
// Driver program
int main()
{
    int N = 8;
    int arr[2 * N - 1] = {1, 1, 1, 1, 2, 2,
                 3, 3, 3, 4, 4, 5, 6, 7, 8};
    if (createTree(arr, N))
    {
        cout << "YES\n";
        for (int i = 0; i < 2 * N - 1; ++i)
            cout << arr[i] << " ";
    }
    else
        cout << "NO\n";
    return 0;
}


Python3
# Python Program to Create RMQ Segment Tree
from typing import List
from math import log2
 
# Returns true if it is possible to construct
# a range minimum segment tree from given array.
def createTree(arr: List[int], N: int) -> bool:
 
    # Store the height of the final tree
    height = int(log2(N)) + 1
 
    # Container to sort and store occurrences of elements
    multi = {}
 
    # Insert elements into the container
    for i in range(2 * N - 1):
        if arr[i] not in multi:
            multi[arr[i]] = 0
        multi[arr[i]] += 1
 
    # Used to store new subtrees created
    Q = [set() for _ in range(height)]
 
    # Insert root into set
    Q[height - 1].add(0)
 
    # Iterate through each unique element in set
    for k, v in multi.items():
 
        # Number of occurrences is greater than height
        # Or, no subtree exists that can accomodate it
        if (v > height or len(Q[v - 1]) == 0):
            return False
 
        # Get the appropriate subtree
        node = sorted(Q[v - 1])[0]
 
        # Delete the subtree we grabbed
        Q[v - 1].remove(sorted(Q[v - 1])[0])
        level = 1
         
        # for (int i = node; i < 2 * N - 1;
        #     i = 2 * i + 1, ++level)
        i = node
        while i < 2 * N - 1:
 
            # Insert new subtree created into root
            if (2 * i + 2 < 2 * N - 1):
                Q[v - level - 1].add(2 * i + 2)
 
            # Insert element into array at position
            arr[i] = k
            level += 1
            i = 2 * i + 1
    return True
 
 
# Driver program
if __name__ == "__main__":
 
    N = 8
    arr = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8]
    if (createTree(arr, N)):
 
        print("YES")
        # for (int i = 0; i < 2 * N - 1; ++i)
        for i in range(2 * N - 1):
            print(arr[i], end=" ")
 
    else:
        print("No")
 
# This code is contributed by sanjeev2552


输出:

YES
1 1 3 1 2 3 4 1 5 2 6 3 7 4 8