📜  段树中的逐级交替OR和XOR操作

📅  最后修改于: 2021-04-17 08:32:43             🧑  作者: Mango

Levelwise OR / XOR交替段树是一个段树,以便在每个级别上,操作OR和XOR交替发生。换句话说,在第1层,左右子树通过“或”运算合并在一起,即父节点=左子节点右子节点,在第2层,左节点和右子树在左边

右子树和右子树通过XOR操作合并在一起,即父节点=左子节点XOR右子节点
这种类型的细分树具有以下类型的结构:

操作(OR)和(XOR)指示执行了哪个操作以合并子节点
给定2 N个叶节点,任务是构建这样的段树并打印根节点

例子:

Input : Leaves = {1, 6, 3, 7, 5, 9, 10, 4}
Output : Value at Root Node = 3
Explanation : The image given above shows the 
segment tree corresponding to the given
set leaf nodes.

这是古典段树的扩展,其中我们将每个节点表示为整数,并通过首先构建左右子树,然后将左右子节点的结果合并到父节点来构建父节点。左右子节点合并到父节点中是通过一致的操作完成的,例如,范围最小查询中的MIN()/ MAX(),Sum,XOR,OR,AND等。通过一致的操作,我们的意思是执行此操作是通过在结果上携带操作OP来将任何节点的左子节点和右子节点合并到父节点中,其中OP是一致的操作。

在此细分树中,我们进行两个操作–和XOR
现在,我们以与传统版本类似的方式构建细分树,但是现在当我们递归传递子树的信息时,我们还将传递有关要在该级别执行的操作的信息,因为这些操作是交替进行的水平地。重要的是要注意,父节点在调用其左子节点和右子节点时,会将相同的操作信息传递给两个子节点,因为它们在同一级别上。

让我们分别用0和1表示两个运算,即OR和XOR。然后,如果在级别i处进行或运算,则在级别(i +1)处进行异或运算。如果级别i的运算为0,则级别(i + 1)的运算为1

Operation at Level (i + 1) = ! (Operation at Level i)
where,
Operation at Level i ∈ {0, 1}

下图显示了段树节点的父子关系:

现在,我们需要查看要在根节点上执行的操作。

如果我们仔细观察图像,那么很容易发现,如果树的高度是偶数,则根节点是其左,右子级的XOR操作的结果,否则是OR操作的结果。

C++
// C++ program to build levelwise OR/XOR alternating
// Segment tree
#include 
 
using namespace std;
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
// operation denotes which operation is carried out
// at that level to merge the left and right child.
// It's either 0 or 1.
void constructSTUtil(int arr[], int ss, int se, int* st,
                                  int si, int operation)
{
    // If there is one element in array, store it
    // in current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then
    // recur for left and right subtrees and store
    // the sum of values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    constructSTUtil(arr, ss, mid, st, si * 2 + 1, !operation);
    constructSTUtil(arr, mid + 1, se, st, si * 2 + 2, !operation);
 
    // merge the left and right subtrees by checking
    // the operation to  be carried. If operation = 1,
    // then do OR else XOR
    if (operation == 1) {
 
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else {
 
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
/* Function to construct segment tree from given array.
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
int* constructST(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    int operationAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, operationAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
int main()
{
 
    // leaf nodes
    int leaves[] = { 1, 6, 3, 7, 5, 9, 10, 4 };
 
    int n = sizeof(leaves) / sizeof(leaves[0]);
 
    // Build the segment tree
    int* segmentTree = constructST(leaves, n);
 
    // Root node is at index 0 considering
    // 0-based indexing in segment Tree
    int rootIndex = 0;
 
    // print value at rootIndex
    cout << "Value at Root Node = " << segmentTree[rootIndex];
}


Java
// Java program to build levelwise OR/XOR alternating
// Segment tree
class GFG{
 
// A utility function to get the middle index from
// corner indexes.
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
// operation denotes which operation is carried out
// at that level to merge the left and right child.
// It's either 0 or 1.
static void constructSTUtil(int arr[], int ss, int se,
                            int st[], int si,
                            boolean operation)
{
     
    // If there is one element in array, store it
    // in current node of segment tree and return
    if (ss == se)
    {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then
    // recur for left and right subtrees and store
    // the sum of values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    constructSTUtil(arr, ss, mid, st,
                    si * 2 + 1, !operation);
    constructSTUtil(arr, mid + 1, se, st,
                    si * 2 + 2, !operation);
 
    // Merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation)
    {
         
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else
    {
         
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
// Function to construct segment tree from
// given array. This function allocates
// memory for segment tree and calls
// constructSTUtil() to fill the allocated memory
static int[] constructST(int arr[], int n)
{
     
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n) /
                            Math.log(2)));
     
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // Allocate memory
    int[] st = new int[max_size];
 
    // Operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    boolean operationAtRoot = !(x % 2 == 0);
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st,
                    0, operationAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
public static void main(String[] args)
{
     
    // Leaf nodes
    int leaves[] = { 1, 6, 3, 7,
                     5, 9, 10, 4 };
 
    int n = leaves.length;
 
    // Build the segment tree
    int[] segmentTree = constructST(leaves, n);
 
    // Root node is at index 0 considering
    // 0-based indexing in segment Tree
    int rootIndex = 0;
 
    // Print value at rootIndex
    System.out.println("Value at Root Node = " +
                       segmentTree[rootIndex]);
}
}
 
// This code is contributed by sanjeev2552


Python3
# Python3 program to build levelwise
# OR/XOR alternating Segment tree
import math
 
# A utility function to get the
#  middle index from corner indexes.
def getMid(s, e):
    return s + (e - s) // 2
 
# A recursive function that constructs
# Segment Tree for array[ss..se].
# 'si' is index of current node in segment
# tree 'st', operation denotes which operation
# is carried out at that level to merge the
# left and right child. It's either 0 or 1.
def constructSTUtil(arr, ss, se, st, si, operation):
 
    # If there is one element in array,
    # store it in current node of segment
    # tree and return
    if (ss == se) :
        st[si] = arr[ss]
        return
     
    # If there are more than one elements,
    # then recur for left and right subtrees
    # and store the sum of values in this node
    mid = getMid(ss, se)
 
    # Build the left and the right subtrees by
    # using the fact that operation at level
    # (i + 1) = ! (operation at level i)
    constructSTUtil(arr, ss, mid, st,
                    si * 2 + 1, not operation)
    constructSTUtil(arr, mid + 1, se, st,
                    si * 2 + 2, not operation)
 
    # merge the left and right subtrees
    # by checking the operation to be
    # carried. If operation = 1, then
    # do OR else XOR
    if (operation == 1) :
 
        # OR operation
        st[si] = (st[2 * si + 1] |
                  st[2 * si + 2])
     
    else :
 
        # XOR operation
        st[si] = (st[2 * si + 1] ^
                  st[2 * si + 2])
 
''' Function to construct segment tree
from given array. This function allocates
memory for segment tree and calls
constructSTUtil() to fill the allocated memory '''
def constructST(arr, n):
 
    # Allocate memory for segment tree
 
    # Height of segment tree
    x = int(math.ceil(math.log2(n)))
 
    # Maximum size of segment tree
    max_size = 2 * int(pow(2, x)) - 1
 
    # Allocate memory
    st = [0] * max_size
 
    # operation = 1(XOR) if Height of tree is
    # even else it is 0(OR) for the root node
    operationAtRoot = (0 if x % 2 == 0 else 1)
 
    # Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1,
                    st, 0, operationAtRoot)
 
    # Return the constructed segment tree
    return st
 
# Driver Code
if __name__ == "__main__":
 
    # leaf nodes
    leaves = [ 1, 6, 3, 7, 5, 9, 10, 4 ]
 
    n = len(leaves)
 
    # Build the segment tree
    segmentTree = constructST(leaves, n)
 
    # Root node is at index 0 considering
    # 0-based indexing in segment Tree
    rootIndex = 0
 
    # print value at rootIndex
    print("Value at Root Node = " ,
           segmentTree[rootIndex])
 
# This code is contributed by ChitraNayal


C#
// C# program to build levelwise OR/XOR
// alternating Segment tree
using System;
 
class GFG{
     
// A utility function to get the middle
// index from corner indexes.
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
  
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
// operation denotes which operation is carried out
// at that level to merge the left and right child.
// It's either 0 or 1.
static void constructSTUtil(int[] arr, int ss, int se,
                            int[] st, int si,
                            bool operation)
{
     
    // If there is one element in array, store it
    // in current node of segment tree and return
    if (ss == se)
    {
        st[si] = arr[ss];
        return;
    }
  
    // If there are more than one elements, then
    // recur for left and right subtrees and store
    // the sum of values in this node
    int mid = getMid(ss, se);
  
    // Build the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    constructSTUtil(arr, ss, mid, st,
                    si * 2 + 1, !operation);
    constructSTUtil(arr, mid + 1, se, st,
                    si * 2 + 2, !operation);
  
    // Merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation)
    {
         
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else
    {
         
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
  
// Function to construct segment tree from
// given array. This function allocates
// memory for segment tree and calls
// constructSTUtil() to fill the allocated memory
static int[] constructST(int[] arr, int n)
{
     
    // Allocate memory for segment tree
  
    // Height of segment tree
    int x = (int)(Math.Ceiling(Math.Log(n) /
                               Math.Log(2)));
      
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.Pow(2, x) - 1;
  
    // Allocate memory
    int[] st = new int[max_size];
  
    // Operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    bool operationAtRoot = !(x % 2 == 0);
  
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st,
                    0, operationAtRoot);
  
    // Return the constructed segment tree
    return st;
}
  
// Driver Code
static public void Main()
{
     
    // Leaf nodes
    int[] leaves = { 1, 6, 3, 7,
                     5, 9, 10, 4 };
  
    int n = leaves.Length;
  
    // Build the segment tree
    int[] segmentTree = constructST(leaves, n);
  
    // Root node is at index 0 considering
    // 0-based indexing in segment Tree
    int rootIndex = 0;
  
    // Print value at rootIndex
    Console.WriteLine("Value at Root Node = " +
                      segmentTree[rootIndex]);
}
}
 
// This code is contributed by rag2127


C++
// C++ program to build levelwise OR/XOR alternating
// Segment tree (with updates)
#include 
 
using namespace std;
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
// operation denotes which operation is carried out
// at that level to merge the left and right child.
// Its either 0 or 1.
void constructSTUtil(int arr[], int ss, int se, int* st,
                                  int si, int operation)
{
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    constructSTUtil(arr, ss, mid, st, si * 2 + 1, !operation);
    constructSTUtil(arr, mid + 1, se, st, si * 2 + 2, !operation);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation == 1) {
 
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else {
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
/* A recursive function to update the nodes which have the given
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is
             in input array.
   val --> Value to be assigned to arr[i] */
void updateValueUtil(int* st, int ss, int se, int i,
                     int val, int si, int operation)
{
    // Base Case: If the input index lies outside
    //  this segment
    if (i < ss || i > se)
        return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == i) {
        st[si] = val;
        return;
    }
 
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    updateValueUtil(st, ss, mid, i, val, 2 * si + 1, !operation);
    updateValueUtil(st, mid + 1, se, i, val, 2 * si + 2, !operation);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation == 1) {
        
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else {
 
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
// The function to update a value in input array and
// segment tree. It uses updateValueUtil() to update the
// value in segment tree
void updateValue(int arr[], int* st, int n, int i, int new_val)
{
    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        printf("Invalid Input");
        return;
    }
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    int operationAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[i] = new_val;
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, new_val, 0, operationAtRoot);
}
 
/* Function to construct segment tree from given array.
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
int* constructST(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    int operationAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, operationAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
int main()
{
    int leaves[] = { 1, 6, 3, 7, 5, 9, 10, 4 };
    int n = sizeof(leaves) / sizeof(leaves[0]);
 
    // Build the segment tree
    int* segmentTree = constructST(leaves, n);
 
    // Root node is at index 0 considering
    // 0-based indexing in segment Tree
    int rootIndex = 0;
 
    // print old value at rootIndex
    cout << "Old Value at Root Node = "
         << segmentTree[rootIndex] << endl;
 
    // perform update leaves[0] = 13
    updateValue(leaves, segmentTree, n, 0, 13);
 
    cout << "New Value at Root Node = "
         << segmentTree[rootIndex];
    return 0;
}


输出:
Value at Root Node = 3

树构建的时间复杂度为O(n)。总共有2n-1个节点,并且在树结构中每个节点的值仅计算一次。

我们还可以以类似方式执行点更新。如果获得更新以更新数组叶子的索引i处的叶子,那么我们将遍历树到叶子节点并执行更新。返回到根节点时,我们通过传递要在每个级别执行的操作并存储将其操作应用于其左子项和右子项的值并将结果存储到来再次构建类似于build()函数的树。该节点。
执行更新后,请考虑以下细分树,
叶[0] = 13

现在,更新后的细分树如下所示:

Updated_segment树

这里黑色的节点表示它们已被更新的事实

C++

// C++ program to build levelwise OR/XOR alternating
// Segment tree (with updates)
#include 
 
using namespace std;
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
// operation denotes which operation is carried out
// at that level to merge the left and right child.
// Its either 0 or 1.
void constructSTUtil(int arr[], int ss, int se, int* st,
                                  int si, int operation)
{
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    constructSTUtil(arr, ss, mid, st, si * 2 + 1, !operation);
    constructSTUtil(arr, mid + 1, se, st, si * 2 + 2, !operation);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation == 1) {
 
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else {
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
/* A recursive function to update the nodes which have the given
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is
             in input array.
   val --> Value to be assigned to arr[i] */
void updateValueUtil(int* st, int ss, int se, int i,
                     int val, int si, int operation)
{
    // Base Case: If the input index lies outside
    //  this segment
    if (i < ss || i > se)
        return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == i) {
        st[si] = val;
        return;
    }
 
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    updateValueUtil(st, ss, mid, i, val, 2 * si + 1, !operation);
    updateValueUtil(st, mid + 1, se, i, val, 2 * si + 2, !operation);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do OR else XOR
    if (operation == 1) {
        
        // OR operation
        st[si] = (st[2 * si + 1] | st[2 * si + 2]);
    }
    else {
 
        // XOR operation
        st[si] = (st[2 * si + 1] ^ st[2 * si + 2]);
    }
}
 
// The function to update a value in input array and
// segment tree. It uses updateValueUtil() to update the
// value in segment tree
void updateValue(int arr[], int* st, int n, int i, int new_val)
{
    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        printf("Invalid Input");
        return;
    }
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    int operationAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[i] = new_val;
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, new_val, 0, operationAtRoot);
}
 
/* Function to construct segment tree from given array.
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
int* constructST(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // operation = 1(XOR) if Height of tree is
    // even else it is 0(OR) for the root node
    int operationAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, operationAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
int main()
{
    int leaves[] = { 1, 6, 3, 7, 5, 9, 10, 4 };
    int n = sizeof(leaves) / sizeof(leaves[0]);
 
    // Build the segment tree
    int* segmentTree = constructST(leaves, n);
 
    // Root node is at index 0 considering
    // 0-based indexing in segment Tree
    int rootIndex = 0;
 
    // print old value at rootIndex
    cout << "Old Value at Root Node = "
         << segmentTree[rootIndex] << endl;
 
    // perform update leaves[0] = 13
    updateValue(leaves, segmentTree, n, 0, 13);
 
    cout << "New Value at Root Node = "
         << segmentTree[rootIndex];
    return 0;
}
输出:
Old Value at Root Node = 3
New Value at Root Node = 11

更新的时间复杂度也是O(Logn)。要更新叶值,我们在每个级别处理一个节点,级别数为O(Logn)。