让我们考虑以下问题以理解段树。
我们有一个数组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