📌  相关文章
📜  细分树| (给定范围的XOR)

📅  最后修改于: 2021-04-17 11:49:24             🧑  作者: Mango

让我们考虑以下问题以理解段树。

我们有一个数组arr [0。 。 。 n-1]。我们应该能够
1找到索引l到r的元素的异或,其中0 <= l <= r <= n-1。

2将数组的指定元素的值更改为新值x。我们需要做arr [i] = x,其中0 <= i <= n-1。

类似于给定范围的总和。

一个简单的解决方案是运行从l到r的循环,并计算给定范围内元素的异或。要更新值,只需做arr [i] = x。第一次操作花费O(n)时间,第二次操作花费O(1)时间。

高效方法
如果查询和更新的次数相等,则可以在O(log n)时间内执行这两个操作。我们可以使用细分树在O(Logn)时间内完成这两项操作。

段树的表示
1.叶节点是输入数组的元素。
2.每个内部节点代表叶节点的某些合并。对于不同的问题,合并可能会有所不同。对于此问题,合并是节点下的叶子的Xor。

树的数组表示形式用于表示段树。对于索引i处的每个节点,左子节点在索引2 * i + 1处,右子节点在索引2 * i + 2处,父节点在(i-1)/ 2处。

表示

查询给定范围的乘积
构造树后,如何使用构造的段树获取Xor。以下是获取元素异或的算法。

int getXor(node, l, r) 
{
   if range of node is within l and r
        return value in node
   else if range of node is completely outside l and r
        return 1
   else
    return getXor(node's left child, l, r) ^ 
           getXor(node's right child, l, r)
}
C++
// C++ program to show segment tree operations
// like construction, query and update
#include 
#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 to get the Xor of
values in given range of the array. The
following are parameters for this function.
    st --> Pointer to segment tree
    si --> Index of current node in the segment tree.
           Initially 0 is passed as root is always
           at index 0.
    ss & se --> Starting and ending indexes of
                the segment represented by current 
                node, i.e., st[si]
    qs & qe --> Starting and ending indexes of 
                query range */
int getXorUtil(int *st, int ss, int se, int qs,
               int qe, int si)
{
    // If segment of this node is a part of given
    // range, then return the Xor of the segment
    if (qs <= ss && qe >= se)
        return st[si];
  
    // If segment of this node is outside
    // the given range
    if (se < qs || ss > qe)
        return 0;
  
    // If a part of this segment overlaps 
    // with the given range
    int mid = getMid(ss, se);
    return getXorUtil(st, ss, mid, qs, qe, 2*si+1) ^
        getXorUtil(st, mid+1, se, qs, qe, 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 getXorUtil()
    i --> index of the element to be updated.
          This index is    in input array.*/
void updateValueUtil(int *st, int ss, int se, int i, 
                     int prev_val, int new_val, int si)
{
    // Base Case: If the input index lies outside
    // the range of 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
    st[si] = (st[si]^prev_val)^new_val;
    if (se != ss)
    {
        int mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i, prev_val, 
                        new_val, 2*si + 1);
        updateValueUtil(st, mid+1, se, i, prev_val, 
                        new_val, 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;
    }
    int temp = arr[i];
    // Update the value in array
    arr[i] = new_val;
  
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n-1, i, temp, new_val, 0);
}
  
// Return Xor of elements in range from index qs (quey start)
// to qe (query end). It mainly uses getXorUtil()
int getXor(int *st, int n, int qs, int qe)
{
    // Check for erroneous input values
    if (qs < 0 || qe > n-1 || qs > qe)
    {
        printf("Invalid Input");
        return 0;
    }
  
    return getXorUtil(st, 0, n-1, qs, qe, 0);
}
  
// A recursive function that constructs
// Segment Tree for array[ss..se]. si is
// index of current node in segment tree st
int constructSTUtil(int arr[], int ss, int se,
                    int *st, int si)
{
    // 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 arr[ss];
    }
  
    // If there are more than one elements,
    // then recur for left and right subtrees
    // and store the Xor of values in this node
    int mid = getMid(ss, se);
    st[si] = constructSTUtil(arr, ss, mid, st, si*2+1) ^
            constructSTUtil(arr, mid+1, se, st, si*2+2);
    return st[si];
}
  
/* 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];
  
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n-1, st, 0);
  
    // Return the constructed segment tree
    return st;
}
  
// Driver program to test above functions
int main()
{
    int arr[] = {1, 3, 5, 7, 9, 11};
    int n = sizeof(arr)/sizeof(arr[0]);
  
    // Build segment tree from given array
    int *st = constructST(arr, n);
  
    // Print Xor of values in array from index 1 to 3
    printf("Xor of values in given range = %d\n",
            getXor(st, n, 0, 2));
  
    // Update: set arr[1] = 10 and update corresponding
    // segment tree nodes
    updateValue(arr, st, n, 1, 10);
  
    // Find Xor after the value is updated
    printf("Updated Xor of values in given range = %d\n",
            getXor(st, n, 0, 2));
    return 0;
}


Java
// Java implementation of the approach 
import java.util.*;
  
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 to get the Xor of
    * values in given range of the array. The
    * following are parameters for this function.
    * st --> Pointer to segment tree
    * si --> Index of current node in the segment tree.
    *     Initially 0 is passed as root is always
    *     at index 0.
    * ss & se --> Starting and ending indexes of
    *             the segment represented by current
    *             node, i.e., st[si]
    * qs & qe --> Starting and ending indexes of
    *             query range
    */
    static int getXorUtil(int[] st, int ss, int se,
                           int qs, int qe, int si)
    {
        // If segment of this node is a part of given
        // range, then return the Xor of the segment
        if (qs <= ss && qe >= se)
            return st[si];
  
        // If segment of this node is outside
        // the given range
        if (se < qs || ss > qe)
            return 0;
  
        // If a part of this segment overlaps
        // with the given range
        int mid = getMid(ss, se);
        return getXorUtil(st, ss, mid, qs, qe, 2 * si + 1) ^ 
               getXorUtil(st, mid + 1, se, qs, qe, 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 getXorUtil()
    * i --> index of the element to be updated.
    *     This index is in input array.
    */
    static void updateValueUtil(int[] st, int ss, int se, int i, 
                                int prev_val, int new_val, int si) 
    {
        // Base Case: If the input index lies outside
        // the range of 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
        st[si] = (st[si] ^ prev_val) ^ new_val;
        if (se != ss) {
            int mid = getMid(ss, se);
            updateValueUtil(st, ss, mid, i, prev_val, 
                            new_val, 2 * si + 1);
            updateValueUtil(st, mid + 1, se, i, prev_val,
                            new_val, 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
    static void updateValue(int arr[], int[] st, int n,
                            int i, int new_val)
    {
        // Check for erroneous input index
        if (i < 0 || i > n - 1) {
            System.out.printf("Invalid Input\n");
            return;
        }
        int temp = arr[i];
        // Update the value in array
        arr[i] = new_val;
  
        // Update the values of nodes in segment tree
        updateValueUtil(st, 0, n - 1, i, temp, new_val, 0);
    }
  
    // Return Xor of elements in range from index qs (quey start)
    // to qe (query end). It mainly uses getXorUtil()
    static int getXor(int[] st, int n, int qs, int qe)
    {
          
        // Check for erroneous input values
        if (qs < 0 || qe > n - 1 || qs > qe)
        {
            System.out.printf("Invalid Input\n");
            return 0;
        }
  
        return getXorUtil(st, 0, n - 1, qs, qe, 0);
    }
  
    // A recursive function that constructs
    // Segment Tree for array[ss..se]. si is
    // index of current node in segment tree st
    static int constructSTUtil(int arr[], int ss, int se,
                                int[] st, int si)
    {
        // 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 arr[ss];
        }
  
        // If there are more than one elements,
        // then recur for left and right subtrees
        // and store the Xor of values in this node
        int mid = getMid(ss, se);
        st[si] = constructSTUtil(arr, ss, mid, st, si * 2 + 1) ^ 
                constructSTUtil(arr, mid + 1, se, st, si * 2 + 2);
        return st[si];
    }
  
    /*
    * 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];
  
        // Fill the allocated memory st
        constructSTUtil(arr, 0, n - 1, st, 0);
  
        // Return the constructed segment tree
        return st;
    }
  
    // Driver Code
    public static void main(String[] args)
    {
        int arr[] = { 1, 3, 5, 7, 9, 11 };
        int n = arr.length;
  
        // Build segment tree from given array
        int[] st = constructST(arr, n);
  
        // Print Xor of values in array from index 1 to 3
        System.out.printf("Xor of values in given range = %d\n", 
                            getXor(st, n, 0, 2));
  
        // Update: set arr[1] = 10 and update corresponding
        // segment tree nodes
        updateValue(arr, st, n, 1, 10);
  
        // Find Xor after the value is updated
        System.out.printf("Updated Xor of values in given range = %d\n", 
                            getXor(st, n, 0, 2));
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Python3 program to show segment tree operations 
# like construction, query and update 
from math import ceil, log2;
  
# A utility function to get the middle 
# index from corner indexes. 
def getMid(s, e) : 
    return s + (e - s) // 2; 
  
""" A recursive function to get the Xor of 
values in given range of the array. The 
following are parameters for this function. 
    st --> Pointer to segment tree 
    si --> Index of current node in the segment tree. 
           Initially 0 is passed as root is always 
           at index 0. 
    ss & se --> Starting and ending indexes of 
                the segment represented by current 
                node, i.e., st[si] 
    qs & qe --> Starting and ending indexes of 
                query range """
def getXorUtil(st, ss, se, qs, qe, si) : 
  
    # If segment of this node is a part of given 
    # range, then return the Xor of the segment 
    if (qs <= ss and qe >= se) :
        return st[si]; 
  
    # If segment of this node is outside 
    # the given range 
    if (se < qs or ss > qe) :
        return 0; 
  
    # If a part of this segment overlaps 
    # with the given range 
    mid = getMid(ss, se); 
      
    return getXorUtil(st, ss, mid, qs, qe, 2 * si + 1) ^ \
           getXorUtil(st, mid + 1, se, qs, qe, 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 getXorUtil() 
i --> index of the element to be updated. 
      This index is in input array."""
def updateValueUtil(st, ss, se, i, 
                    prev_val, new_val, si) :
      
    # Base Case: If the input index lies 
    # outside the range of this segment 
    if (i < ss or i > se) :
        return; 
  
    # If the input index is in range of this node, 
    # then update the value of the node and its children 
    st[si] = (st[si] ^ prev_val) ^ new_val; 
    if (se != ss) :
      
        mid = getMid(ss, se); 
        updateValueUtil(st, ss, mid, i, prev_val, 
                            new_val, 2 * si + 1); 
        updateValueUtil(st, mid + 1, se, i, 
            prev_val, new_val, 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 
def updateValue(arr, st, n, i, new_val) :
  
    # Check for erroneous input index 
    if (i < 0 or i > n - 1) :
  
        print("Invalid Input"); 
        return; 
      
    temp = arr[i]; 
      
    # Update the value in array 
    arr[i] = new_val; 
  
    # Update the values of nodes in segment tree 
    updateValueUtil(st, 0, n - 1, i, temp, new_val, 0); 
  
# Return Xor of elements in range from 
# index qs (quey start) to qe (query end).
# It mainly uses getXorUtil() 
def getXor(st, n, qs, qe) :
  
    # Check for erroneous input values 
    if (qs < 0 or qe > n - 1 or qs > qe) :
        print("Invalid Input"); 
        return 0; 
  
    return getXorUtil(st, 0, n - 1, qs, qe, 0); 
  
# A recursive function that constructs 
# Segment Tree for array[ss..se]. si is 
# index of current node in segment tree st 
def constructSTUtil(arr, ss, se, st, si) :
                          
    # 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 arr[ss]; 
  
    # If there are more than one elements, 
    # then recur for left and right subtrees 
    # and store the Xor of values in this node 
    mid = getMid(ss, se); 
    st[si] = constructSTUtil(arr, ss, mid, st, si * 2 + 1) ^ \
             constructSTUtil(arr, mid + 1, se, st, si * 2 + 2); 
      
    return st[si]; 
  
""" 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)(ceil(log2(n))); 
  
    # Maximum size of segment tree 
    max_size = 2 * (int)(2**x) - 1; 
  
    # Allocate memory 
    st = [0] * (max_size); 
  
    # Fill the allocated memory st 
    constructSTUtil(arr, 0, n - 1, st, 0); 
  
    # Return the constructed segment tree 
    return st; 
  
# Driver Code
if __name__ == "__main__" : 
  
    arr = [1, 3, 5, 7, 9, 11]; 
    n = len(arr); 
  
    # Build segment tree from given array 
    st = constructST(arr, n); 
  
    # Print Xor of values in array from index 1 to 3 
    print("Xor of values in given range =", 
                      getXor(st, n, 0, 2)); 
  
    # Update: set arr[1] = 10 and update 
    # corresponding segment tree nodes 
    updateValue(arr, st, n, 1, 10); 
  
    # Find Xor after the value is updated 
    print("Updated Xor of values in given range =",
                              getXor(st, n, 0, 2)); 
  
# This code is contributed by AnkitRai01


输出:

Xor of values in given range = 7
Updated Xor of values in given range = 14