📌  相关文章
📜  使用段树查询给定范围内的偶数和元素的计数。

📅  最后修改于: 2021-05-17 06:01:59             🧑  作者: Mango

给定N个元素的数组arr [] ,任务是回答Q个查询,每个查询都有两个整数LR。对于每个查询,任务是找到数字总和为偶数的子数组arr [L…R]中的元素数量。
例子:

天真的方法:

  • 通过简单地从索引LR遍历数组,找到每个查询的答案,并在数组元素具有偶数位总和时,将计数加1 。这种方法的时间复杂度将是O(n * q)

高效的方法:
这个想法是建立一个细分树。

  1. 段树的表示形式:
    • 叶节点是输入数组的元素。
    • 每个内部节点包含的叶子数在其下具有所有叶子的偶数和。
  2. 从给定数组构造细分树:
    • 我们从一个段arr [0开始。 。 。 n-1]。每次我们将当前段分为两半(如果尚未将其变为长度为1的段),然后在两个半段上调用相同的过程,则对于每个这样的段,我们存储具有偶数和的元素数它下面的所有节点。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
 
// Function to find the digit sum
// for a number
int digitSum(int num)
{
    int sum = 0;
    while (num) {
        sum += (num % 10);
        num /= 10;
    }
 
    return sum;
}
 
// Procedure to build the segment tree
void buildTree(vector& tree, int* arr,
               int index, int s, int e)
{
 
    // Reached the leaf node
    // of the segment tree
    if (s == e) {
        if (digitSum(arr[s]) & 1)
            tree[index] = 0;
        else
            tree[index] = 1;
        return;
    }
 
    // Recursively call the buildTree
    // on both the nodes of the tree
    int mid = (s + e) / 2;
    buildTree(tree, arr, 2 * index,
              s, mid);
    buildTree(tree, arr, 2 * index + 1,
              mid + 1, e);
 
    tree[index] = tree[2 * index]
                + tree[2 * index + 1];
}
 
// Query procedure to get the answer
// for each query l and r are
// query range
int query(vector tree, int index,
          int s, int e, int l, int r)
{
 
    // Out of bound or no overlap
    if (r < s || l > e)
        return 0;
 
    // Complete overlap
    // Query range completely lies in
    // the segment tree node range
    if (s >= l && e <= r) {
        return tree[index];
    }
 
    // Partially overlap
    // Query range partially lies in
    // the segment tree node range
    int mid = (s + e) / 2;
    return (query(tree, 2 * index, s,
                  mid, l, r)
            + query(tree, 2 * index + 1,
                    mid + 1, e, l, r));
}
 
// Driver code
int main()
{
    int arr[] = { 7, 3, 19, 13, 5, 4 };
    int n = sizeof(arr) / sizeof(arr[0]);
    vector tree(4 * n + 1);
 
    int L = 1, R = 5;
 
    buildTree(tree, arr, 1, 0, n - 1);
 
    cout << query(tree, 1, 0, n - 1, L, R)
         << endl;
    return 0;
}


Java
// Java implementation of the approach
import java.util.*;
class GFG{
 
// Function to find the digit sum
// for a number
static int digitSum(int num)
{
    int sum = 0;
    while (num > 0)
    {
        sum += (num % 10);
        num /= 10;
    }
    return sum;
}
 
// Procedure to build the segment tree
static void buildTree(int []tree, int []arr,
                int index, int s, int e)
{
 
    // Reached the leaf node
    // of the segment tree
    if (s == e)
    {
        if (digitSum(arr[s]) % 2 == 1)
            tree[index] = 0;
        else
            tree[index] = 1;
        return;
    }
 
    // Recursively call the buildTree
    // on both the nodes of the tree
    int mid = (s + e) / 2;
    buildTree(tree, arr, 2 * index,
              s, mid);
    buildTree(tree, arr, 2 * index + 1,
              mid + 1, e);
 
    tree[index] = tree[2 * index] +
                    tree[2 * index + 1];
}
 
// Query procedure to get the answer
// for each query l and r are
// query range
static int query(int []tree, int index,
                 int s, int e,
                 int l, int r)
{
 
    // Out of bound or no overlap
    if (r < s || l > e)
        return 0;
 
    // Complete overlap
    // Query range completely lies in
    // the segment tree node range
    if (s >= l && e <= r)
    {
        return tree[index];
    }
 
    // Partially overlap
    // Query range partially lies in
    // the segment tree node range
    int mid = (s + e) / 2;
    return (query(tree, 2 * index, s,
                  mid, l, r) +
            query(tree, 2 * index + 1,
                  mid + 1, e, l, r));
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 7, 3, 19, 13, 5, 4 };
    int n = arr.length;
    int []tree = new int[4 * n + 1];
 
    int L = 1, R = 5;
 
    buildTree(tree, arr, 1, 0, n - 1);
 
    System.out.print(query(tree, 1, 0,
                           n - 1, L, R) + "\n");
}
}
 
// This code is contributed by gauravrajput1


Python3
# Python3 implementation of the above approach
 
# Function to find the digit sum
# for a number
def digitSum(num):
     
    sum = 0;
    while (num):
        sum += (num % 10)
        num //= 10
     
    return sum
 
# Procedure to build the segment tree
def buildTree(tree, arr, index, s, e):
 
    # Reached the leaf node
    # of the segment tree
    if (s == e):
        if (digitSum(arr[s]) & 1):
            tree[index] = 0
        else:
            tree[index] = 1
        return
 
    # Recursively call the buildTree
    # on both the nodes of the tree
    mid = (s + e) // 2
    buildTree(tree, arr, 2 * index,
              s, mid)
    buildTree(tree, arr, 2 * index + 1,
              mid + 1, e)
 
    tree[index] = (tree[2 * index] +
                   tree[2 * index + 1])
 
# Query procedure to get the answer
# for each query l and r are
# query range
def query(tree, index, s, e, l, r):
 
    # Out of bound or no overlap
    if (r < s or l > e):
        return 0
 
    # Complete overlap
    # Query range completely lies in
    # the segment tree node range
    if (s >= l and e <= r):
        return tree[index]
 
    # Partially overlap
    # Query range partially lies in
    # the segment tree node range
    mid = (s + e) // 2
    return (query(tree, 2 * index,
                  s, mid, l, r) +
            query(tree, 2 * index + 1,
                  mid + 1, e, l, r))
 
# Driver code
arr = [ 7, 3, 19, 13, 5, 4 ]
n = len(arr)
 
tree = [0] * (4 * n + 1)
 
L = 1
R = 5
 
buildTree(tree, arr, 1, 0, n - 1);
 
print(query(tree, 1, 0, n - 1, L, R))
 
# This code is contributed by Apurvaraj


C#
// C# implementation of the approach
using System;
class GFG{
 
// Function to find the digit sum
// for a number
static int digitSum(int num)
{
    int sum = 0;
    while (num > 0)
    {
        sum += (num % 10);
        num /= 10;
    }
    return sum;
}
 
// Procedure to build the segment tree
static void buildTree(int []tree, int []arr,
                      int index, int s, int e)
{
 
    // Reached the leaf node
    // of the segment tree
    if (s == e)
    {
        if (digitSum(arr[s]) % 2 == 1)
            tree[index] = 0;
        else
            tree[index] = 1;
        return;
    }
 
    // Recursively call the buildTree
    // on both the nodes of the tree
    int mid = (s + e) / 2;
    buildTree(tree, arr, 2 * index,
              s, mid);
    buildTree(tree, arr, 2 * index + 1,
              mid + 1, e);
 
    tree[index] = tree[2 * index] +
                  tree[2 * index + 1];
}
 
// Query procedure to get the answer
// for each query l and r are
// query range
static int query(int []tree, int index,
                 int s, int e,
                 int l, int r)
{
 
    // Out of bound or no overlap
    if (r < s || l > e)
        return 0;
 
    // Complete overlap
    // Query range completely lies in
    // the segment tree node range
    if (s >= l && e <= r)
    {
        return tree[index];
    }
 
    // Partially overlap
    // Query range partially lies in
    // the segment tree node range
    int mid = (s + e) / 2;
    return (query(tree, 2 * index, s,
                  mid, l, r) +
            query(tree, 2 * index + 1,
                  mid + 1, e, l, r));
}
 
// Driver code
public static void Main(String[] args)
{
    int []arr = { 7, 3, 19, 13, 5, 4 };
    int n = arr.Length;
    int []tree = new int[4 * n + 1];
 
    int L = 1, R = 5;
 
    buildTree(tree, arr, 1, 0, n - 1);
 
    Console.Write(query(tree, 1, 0,
                        n - 1, L, R) + "\n");
}
}
 
// This code is contributed by gauravrajput1


输出:
3






时间复杂度: O(Q * log(N))