给定大小为N的数组,可以有以下类型的多个查询。
- update(l,r) :更新时,翻转(将a [i]乘以-1)a [i]的值,其中l <= i <= r。简单来说,将a [i]的符号更改为给定范围。
- query(l,r) :查询时,打印给定范围(包括l和r)中数组的总和。
例子 :
Input : arr[] = { 1, 2, 3, 4, 5 }
update(0, 2)
query(0, 4)
Output: 3
After applying update operation array becomes { -1, -2, -3, 4, 5 } .
So the sum is 3
Input : arr[] = { 1, 2, 3, 4, 5 }
update(0, 4)
query(0, 4)
Output: -15
After applying update operation array becomes { -1, -2, -3, -4, -5 } .
So the sum is -15
先决条件:
- 段树
- 分段树中的延迟传播
方法 :
创建一个分段树,每个节点都将存储其左,右子节点的和,直到它是存储该数组的叶节点为止。
对于更新操作:
创建一个名为lazy的树,其大小与上述分段树的大小相同,其中树存储其子项和lazy的总和,无论是否要求翻转它们。如果将某个范围的惰性设置为1,则需要翻转该范围内的所有值。为了进行更新,使用了以下操作–
- 如果当前段树的lazy设置为1,则通过更改符号来更新当前段树节点,因为需要翻转其值,并且还翻转其子级的lazy的值并将其自己的lazy重置为0。
- 如果当前节点的范围完全在更新查询范围之内,则通过更改其符号来更新当前节点,如果不是叶节点,还可以翻转其子节点的lazy值。
- 如果当前节点的范围与更新范围重叠,则对其子节点进行递归,并使用其子节点的总和来更新当前节点。
对于查询操作:
如果lazy设置为1,则更改当前节点的符号,并将lazy当前节点重置为0,如果不是叶节点,则翻转其子节点的lazy值。然后像段树一样进行简单查询。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
using namespace std;
#define MAX 15
int tree[MAX] = { 0 };
int lazy[MAX] = { 0 };
// Function to build the segment tree
void build(int arr[],int node, int a, int b)
{
if (a == b) {
tree[node] = arr[a];
return;
}
// left child
build(arr,2 * node, a, (a + b) / 2);
// right child
build(arr,2 * node + 1, 1 + (a + b) / 2, b);
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
void update_tree(int node, int a,
int b, int i, int j)
{
// If lazy of node is 1 then
// value in current node
// needs to be flipped
if (lazy[node] != 0) {
// Update it
tree[node] = tree[node] * (-1);
if (a != b) {
// flip value in lazy
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
// Reset the node lazy value
lazy[node] = 0;
}
// Current segment is not
// within range [i, j]
if (a > b || a > j || b < i)
return;
// Segment is fully
// within range
if (a >= i && b <= j) {
tree[node] = tree[node] * (-1);
// Not leaf node
if (a != b) {
// Flip the value as if lazy is
// 1 and again asked to flip
// value then without flipping
// value two times
lazy[node * 2] =
!(lazy[node * 2]);
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
return;
}
// Updating left child
update_tree(node * 2, a,
(a + b) / 2, i, j);
// Updating right child
update_tree(1 + node * 2, 1 +
(a + b) / 2, b, i, j);
// Updating root with
// sum of its child
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
int query_tree(int node, int a,
int b, int i, int j)
{
// Out of range
if (a > b || a > j || b < i)
return 0;
// If lazy of node is 1 then value
// in current node needs to be flipped
if (lazy[node] != 0) {
tree[node] = tree[node] * (-1);
if (a != b) {
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
lazy[node] = 0;
}
// Current segment is totally
// within range [i, j]
if (a >= i && b <= j)
return tree[node];
// Query left child
int q1 = query_tree(node * 2, a,
(a + b) / 2, i, j);
// Query right child
int q2 = query_tree(1 + node * 2,
1 + (a + b) / 2, b, i, j);
// Return final result
return q1 + q2;
}
int main()
{
int arr[]={1,2,3,4,5};
int n=sizeof(arr)/sizeof(arr[0]);
// Building segment tree
build(arr,1, 0, n - 1);
// Array is { 1, 2, 3, 4, 5 }
cout << query_tree(1, 0, n - 1, 0, 4) << endl;
// Flip range 0 to 4
update_tree(1, 0, n - 1, 0, 4);
// Array becomes { -1, -2, -3, -4, -5 }
cout << query_tree(1, 0, n - 1, 0, 4) << endl;
// Flip range 0 t0 2
update_tree(1, 0, n - 1, 0, 2);
// Array becomes { 1, 2, 3, -4, -5 }
cout << query_tree(1, 0, n - 1, 0, 4) << endl;
}
Java
// Java implementation of the approach
class GFG
{
static final int MAX = 15;
static int tree[] = new int[MAX];
static boolean lazy[] = new boolean[MAX];
// Function to build the segment tree
static void build(int arr[],int node, int a, int b)
{
if (a == b)
{
tree[node] = arr[a];
return;
}
// left child
build(arr,2 * node, a, (a + b) / 2);
// right child
build(arr,2 * node + 1, 1 + (a + b) / 2, b);
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
static void update_tree(int node, int a,
int b, int i, int j)
{
// If lazy of node is 1 then
// value in current node
// needs to be flipped
if (lazy[node] != false)
{
// Update it
tree[node] = tree[node] * (-1);
if (a != b)
{
// flip value in lazy
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
// Reset the node lazy value
lazy[node] = false;
}
// Current segment is not
// within range [i, j]
if (a > b || a > j || b < i)
return;
// Segment is fully
// within range
if (a >= i && b <= j)
{
tree[node] = tree[node] * (-1);
// Not leaf node
if (a != b)
{
// Flip the value as if lazy is
// 1 and again asked to flip
// value then without flipping
// value two times
lazy[node * 2] =
!(lazy[node * 2]);
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
return;
}
// Updating left child
update_tree(node * 2, a,
(a + b) / 2, i, j);
// Updating right child
update_tree(1 + node * 2, 1 +
(a + b) / 2, b, i, j);
// Updating root with
// sum of its child
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
static int query_tree(int node, int a,
int b, int i, int j)
{
// Out of range
if (a > b || a > j || b < i)
return 0;
// If lazy of node is 1 then value
// in current node needs to be flipped
if (lazy[node] != false)
{
tree[node] = tree[node] * (-1);
if (a != b)
{
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
lazy[node] = false;
}
// Current segment is totally
// within range [i, j]
if (a >= i && b <= j)
return tree[node];
// Query left child
int q1 = query_tree(node * 2, a,
(a + b) / 2, i, j);
// Query right child
int q2 = query_tree(1 + node * 2,
1 + (a + b) / 2, b, i, j);
// Return final result
return q1 + q2;
}
// Driver code
public static void main(String[] args)
{
int arr[]={1, 2, 3, 4, 5};
int n=arr.length;
// Building segment tree
build(arr,1, 0, n - 1);
// Array is { 1, 2, 3, 4, 5 }
System.out.print(query_tree(1, 0, n - 1, 0, 4) +"\n");
// Flip range 0 to 4
update_tree(1, 0, n - 1, 0, 4);
// Array becomes { -1, -2, -3, -4, -5 }
System.out.print(query_tree(1, 0, n - 1, 0, 4) +"\n");
// Flip range 0 t0 2
update_tree(1, 0, n - 1, 0, 2);
// Array becomes { 1, 2, 3, -4, -5 }
System.out.print(query_tree(1, 0, n - 1, 0, 4) +"\n");
}
}
// This code contributed by Rajput-Ji
Python3
# Python3 implementation of the approach
MAX = 15
tree = [0]*MAX
lazy = [0]*MAX
# Function to build the segment tree
def build(arr,node, a, b):
if (a == b):
tree[node] = arr[a]
return
# left child
build(arr,2 * node, a, (a + b) // 2)
# right child
build(arr,2 * node + 1, 1 + (a + b) // 2, b)
tree[node] = tree[node * 2] +tree[node * 2 + 1]
def update_tree(node, a,b, i, j):
# If lazy of node is 1 then
# value in current node
# needs to be flipped
if (lazy[node] != 0):
# Update it
tree[node] = tree[node] * (-1)
if (a != b):
# flip value in lazy
lazy[node * 2] =not (lazy[node * 2])
# flip value in lazy
lazy[node * 2 + 1] =not (lazy[node * 2 + 1])
# Reset the node lazy value
lazy[node] = 0
# Current segment is not
# within range [i, j]
if (a > b or a > j or b < i):
return
# Segment is fully
# within range
if (a >= i and b <= j):
tree[node] = tree[node] * (-1)
# Not leaf node
if (a != b):
# Flip the value as if lazy is
# 1 and again asked to flip
# value then without flipping
# value two times
lazy[node * 2] = not (lazy[node * 2])
lazy[node * 2 + 1] = not (lazy[node * 2 + 1])
return
# Updating left child
update_tree(node * 2, a,(a + b) // 2, i, j)
# Updating right child
update_tree(1 + node * 2, 1 +(a + b) // 2, b, i, j)
# Updating root with
# sum of its child
tree[node] = tree[node * 2] +tree[node * 2 + 1]
def query_tree(node, a,b, i, j):
# Out of range
if (a > b or a > j or b < i):
return 0
# If lazy of node is 1 then value
# in current node needs to be flipped
if (lazy[node] != 0):
tree[node] = tree[node] * (-1)
if (a != b):
lazy[node * 2] =not (lazy[node * 2])
# flip value in lazy
lazy[node * 2 + 1] = not (lazy[node * 2 + 1])
lazy[node] = 0
# Current segment is totally
# within range [i, j]
if (a >= i and b <= j):
return tree[node]
# Query left child
q1 = query_tree(node * 2, a,(a + b) // 2, i, j)
# Query right child
q2 = query_tree(1 + node * 2,1 + (a + b) // 2, b, i, j)
# Return final result
return q1 + q2
# Driver code
if __name__ == '__main__':
arr=[1,2,3,4,5]
n=len(arr)
# Building segment tree
build(arr,1, 0, n - 1)
# Array is { 1, 2, 3, 4, 5
print(query_tree(1, 0, n - 1, 0, 4))
# Flip range 0 to 4
update_tree(1, 0, n - 1, 0, 4)
# Array becomes { -1, -2, -3, -4, -5
print(query_tree(1, 0, n - 1, 0, 4))
# Flip range 0 t0 2
update_tree(1, 0, n - 1, 0, 2)
# Array becomes { 1, 2, 3, -4, -5
print(query_tree(1, 0, n - 1, 0, 4))
# This code is contributed by mohit kumar 29
C#
// C# implementation of the approach
using System;
class GFG
{
static readonly int MAX = 15;
static int []tree = new int[MAX];
static bool []lazy = new bool[MAX];
// Function to build the segment tree
static void build(int []arr,int node, int a, int b)
{
if (a == b)
{
tree[node] = arr[a];
return;
}
// left child
build(arr, 2 * node, a, (a + b) / 2);
// right child
build(arr, 2 * node + 1, 1 + (a + b) / 2, b);
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
static void update_tree(int node, int a,
int b, int i, int j)
{
// If lazy of node is 1 then
// value in current node
// needs to be flipped
if (lazy[node] != false)
{
// Update it
tree[node] = tree[node] * (-1);
if (a != b)
{
// flip value in lazy
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
// Reset the node lazy value
lazy[node] = false;
}
// Current segment is not
// within range [i, j]
if (a > b || a > j || b < i)
return;
// Segment is fully
// within range
if (a >= i && b <= j)
{
tree[node] = tree[node] * (-1);
// Not leaf node
if (a != b)
{
// Flip the value as if lazy is
// 1 and again asked to flip
// value then without flipping
// value two times
lazy[node * 2] =
!(lazy[node * 2]);
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
return;
}
// Updating left child
update_tree(node * 2, a,
(a + b) / 2, i, j);
// Updating right child
update_tree(1 + node * 2, 1 +
(a + b) / 2, b, i, j);
// Updating root with
// sum of its child
tree[node] = tree[node * 2] +
tree[node * 2 + 1];
}
static int query_tree(int node, int a,
int b, int i, int j)
{
// Out of range
if (a > b || a > j || b < i)
return 0;
// If lazy of node is 1 then value
// in current node needs to be flipped
if (lazy[node] != false)
{
tree[node] = tree[node] * (-1);
if (a != b)
{
lazy[node * 2] =
!(lazy[node * 2]);
// flip value in lazy
lazy[node * 2 + 1] =
!(lazy[node * 2 + 1]);
}
lazy[node] = false;
}
// Current segment is totally
// within range [i, j]
if (a >= i && b <= j)
return tree[node];
// Query left child
int q1 = query_tree(node * 2, a,
(a + b) / 2, i, j);
// Query right child
int q2 = query_tree(1 + node * 2,
1 + (a + b) / 2, b, i, j);
// Return readonly result
return q1 + q2;
}
// Driver code
public static void Main(String[] args)
{
int []arr = {1, 2, 3, 4, 5};
int n = arr.Length;
// Building segment tree
build(arr, 1, 0, n - 1);
// Array is { 1, 2, 3, 4, 5 }
Console.Write(query_tree(1, 0, n - 1, 0, 4) +"\n");
// Flip range 0 to 4
update_tree(1, 0, n - 1, 0, 4);
// Array becomes { -1, -2, -3, -4, -5 }
Console.Write(query_tree(1, 0, n - 1, 0, 4) +"\n");
// Flip range 0 t0 2
update_tree(1, 0, n - 1, 0, 2);
// Array becomes { 1, 2, 3, -4, -5 }
Console.Write(query_tree(1, 0, n - 1, 0, 4) +"\n");
}
}
// This code is contributed by Rajput-Ji
输出:
15
-15
-3
时间复杂度: O(log(N))