📌  相关文章
📜  数组范围查询可通过更新来计算强大的数字

📅  最后修改于: 2021-05-17 16:21:44             🧑  作者: Mango

给定一个由N个整数组成的数组,任务是对给定的数组执行以下两个操作:

如果对每个素数p,p 2也将其除,则数字N被称为有力数
先决条件:强大的数字,段树
例子:

方法:
由于我们需要处理点更新和范围查询,因此我们将使用细分树来解决该问题。

  1. 我们将预先计算所有强大的数,直到arr [i]可以取最大值,例如MAX
    此操作的时间复杂度为O(MAX * sqrt(MAX))
  2. 构建段树:
    • 可以使用段树将问题简化为子数组总和。
    • 现在,我们可以构建段树,其中叶节点将表示1 (当数字是有效数字时)或0 (当数字不是有效数字时)。所有内部节点都将具有其两个子节点的总和。
  3. 点更新:
    • 要更新元素,我们需要查看元素所在的间隔,并在左边或右边的子元素上相应地递归。如果要更新的元素是强大的数字,则我们将叶子更新为1,否则更新为0。
  4. 范围查询:
    • 每当我们收到从L到R的查询时,我们都可以在段树中查询L到R范围内的节点总数,这又代表了L到R范围内的幂数的数量。

下面是上述方法的实现:

C++
// C++ Program to find the number
// of Powerful numbers in subarray
// using segment tree
#include 
using namespace std;
 
#define MAX 100000
 
// Size of segment tree = 2^{log(MAX)+1}
int tree[3 * MAX];
int arr[MAX];
bool powerful[MAX + 1];
 
// Function to check if the
// number is powerful
bool isPowerful(int n)
{
    // First divide the number
    // repeatedly by 2
    while (n % 2 == 0)
    {
        int power = 0;
        while (n % 2 == 0)
        {
            n /= 2;
            power++;
        }
 
        // If only 2^1 divides
        // n (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // If n is not a power of 2 then
    // this loop will execute
    // repeat above process
    for (int factor = 3; factor
         <= sqrt(n); factor += 2)
    {
        // Find highest power of
        // "factor" that divides n
        int power = 0;
        while (n % factor == 0)
        {
            n = n / factor;
            power++;
        }
 
        // If only factor^1 divides n
        // (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // n must be 1 now if it is not
    // a prime numenr. Since prime
    // numbers are not powerful,
    // we return false if n is not 1.
    return (n == 1);
}
 
// Function to build the array
void BuildArray(int input[], int n)
{
    for (int i = 0; i < n; i++)
    {
        // Check if input[i] is
        // a Powerful number or not
        if (powerful[input[i]])
            arr[i] = 1;
 
        else
            arr[i] = 0;
    }
    return;
 
}
 
// 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 --> 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[index]
*/
void constructSTUtil(int si, int ss,
                     int se)
{
    if (ss == se) {
        // If there is one element
        // in array
        tree[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements,
    // then recur for left and right subtrees
    // and store the sum of the two
    // values in this node
    else {
        int mid = getMid(ss, se);
         
        constructSTUtil(2 * si + 1,
                        ss, mid);
         
        constructSTUtil(2 * si + 2,
                        mid + 1, se);
         
        tree[si] = tree[2 * si + 1]
                  + tree[2 * si + 2];
    }
}
 
/* A recursive function to update the
nodes which have the given index
in their range.
 
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[index]
 
ind --> Index of array to be updated
 
val --> The new value to be updated
 
*/
void updateValueUtil(int si, int ss, int se,
                     int idx, int val)
{
    // Leaf node
    if (ss == se) {
        tree[si] = tree[si] - arr[idx] + val;
        arr[idx] = val;
    }
    else {
        int mid = getMid(ss, se);
         
        // If idx is in the left child,
        // recurse on the left child
        if (ss <= idx and idx <= mid)
            updateValueUtil(2 * si + 1, ss,
                            mid, idx, val);
 
        // If idx is in the right child,
        // recurse on the right child
        else
            updateValueUtil(2 * si + 2, mid + 1,
                            se, idx, val);
 
        // Internal node will have the sum
        // of both of its children
        tree[si] = tree[2 * si + 1]
                   + tree[2 * si + 2];
    }
}
 
/* A recursive function to get the number
of Powerful numbers in a given
range of array indexes
 
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[index]
l & r --> Starting and ending indexes of
          query range
 
 
 */
int queryPowerfulUtil(int si, int ss, int se,
                      int l, int r)
{
    // If segment of this node is
    // outside the given range
    if (r < ss or se < l) {
        return 0;
    }
    // If segment of this node is a part
    // of given range, then return the
    // number of composites
    // in the segment
    if (l <= ss and se <= r) {
        return tree[si];
    }
 
    // If a part of this segment
    // overlaps with the given range
    int mid = getMid(ss, se);
    int p1 = queryPowerfulUtil(2 * si + 1,
                               ss, mid, l,
                               r);
    int p2 = queryPowerfulUtil(2 * si + 2,
                               mid + 1,
                               se, l, r);
    return (p1 + p2);
}
 
void queryPowerful(int n, int l, int r)
{
    printf("Number of Powerful numbers between %d to %d = %d\n",
           l, r, queryPowerfulUtil(0, 0,
                                   n - 1,
                                   l, r));
}
 
void updateValue(int n, int ind, int val)
{
    // If val is a Powerful number
    // we will update 1 in tree
    if (powerful[val])
        updateValueUtil(0, 0, n - 1,
                        ind, 1);
    else
        updateValueUtil(0, 0, n - 1,
                        ind, 0);
}
 
void precomputePowerful()
{
 
    memset(powerful, false,
           sizeof(powerful));
 
    // Computing all Powerful
    // numbers till MAX
    for (int i = 1; i <= MAX; i++)
    {
        // If the number is
        // Powerful make
        // powerful[i] = true
        if (isPowerful(i))
            powerful[i] = true;
    }
}
 
// Driver Code
int main()
{
    // Precompute all the powerful
    // numbers till MAX
    precomputePowerful();
 
    // Input array
    int input[] = { 4, 5, 18, 27, 40, 144 };
     
    // Size of Input array
    int n = sizeof(input) / sizeof(input[0]);
 
    // Build the array.
    BuildArray(input, n);
     
    // Build segment tree from
    // given array
    constructSTUtil(0, 0, n - 1);
 
    // Query 1: Query(L = 0, R = 3)
    int l = 0, r = 3;
    queryPowerful(n, l, r);
 
    // Query 2: Update(i = 1, x = 9),
    // i.e Update input[i] to x
    int i = 1;
    int val = 9;
    updateValue(n, i, val);
 
    // Query 3: Query(L = 0, R = 3)
    queryPowerful(n, l, r);
 
 
    return 0;
}


Java
// Java program to find the number
// of Powerful numbers in subarray
// using segment tree
import java.util.*;
 
class GFG{
 
static final int MAX = 100000;
 
// Size of segment tree = 2^{log(MAX)+1}
static int []tree = new int[3 * MAX];
static int []arr = new int[MAX];
static boolean []powerful = new boolean[MAX + 1];
 
// Function to check if the
// number is powerful
static boolean isPowerful(int n)
{
     
    // First divide the number
    // repeatedly by 2
    while (n % 2 == 0)
    {
        int power = 0;
        while (n % 2 == 0)
        {
            n /= 2;
            power++;
        }
 
        // If only 2^1 divides
        // n (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // If n is not a power of 2 then
    // this loop will execute
    // repeat above process
    for(int factor = 3;
            factor <= Math.sqrt(n);
            factor += 2)
    {
         
        // Find highest power of
        // "factor" that divides n
        int power = 0;
        while (n % factor == 0)
        {
            n = n / factor;
            power++;
        }
 
        // If only factor^1 divides n
        // (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // n must be 1 now if it is not
    // a prime numenr. Since prime
    // numbers are not powerful,
    // we return false if n is not 1.
    return (n == 1);
}
 
// Function to build the array
static void BuildArray(int input[], int n)
{
    for(int i = 0; i < n; i++)
    {
         
        // Check if input[i] is
        // a Powerful number or not
        if (powerful[input[i]])
            arr[i] = 1;
 
        else
            arr[i] = 0;
    }
    return;
}
 
// 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 -. 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[index]
*/
static void constructSTUtil(int si, int ss,
                            int se)
{
    if (ss == se)
    {
         
        // If there is one element
        // in array
        tree[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements,
    // then recur for left and right subtrees
    // and store the sum of the two
    // values in this node
    else
    {
        int mid = getMid(ss, se);
         
        constructSTUtil(2 * si + 1,
                        ss, mid);
         
        constructSTUtil(2 * si + 2,
                        mid + 1, se);
         
        tree[si] = tree[2 * si + 1] +
                   tree[2 * si + 2];
    }
}
 
/* A recursive function to update the
nodes which have the given index
in their range.
 
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[index]
 
ind -. Index of array to be updated
 
val -. The new value to be updated
 
*/
static void updateValueUtil(int si, int ss, int se,
                            int idx, int val)
{
     
    // Leaf node
    if (ss == se)
    {
        tree[si] = tree[si] - arr[idx] + val;
        arr[idx] = val;
    }
    else
    {
        int mid = getMid(ss, se);
         
        // If idx is in the left child,
        // recurse on the left child
        if (ss <= idx && idx <= mid)
            updateValueUtil(2 * si + 1, ss,
                            mid, idx, val);
 
        // If idx is in the right child,
        // recurse on the right child
        else
            updateValueUtil(2 * si + 2, mid + 1,
                            se, idx, val);
 
        // Internal node will have the sum
        // of both of its children
        tree[si] = tree[2 * si + 1] +
                   tree[2 * si + 2];
    }
}
 
/* A recursive function to get the number
of Powerful numbers in a given
range of array indexes
 
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[index]
l & r -. Starting and ending indexes of
        query range
 
*/
static int queryPowerfulUtil(int si, int ss,
                             int se, int l, int r)
{
     
    // If segment of this node is
    // outside the given range
    if (r < ss || se < l)
    {
        return 0;
    }
     
    // If segment of this node is a part
    // of given range, then return the
    // number of composites
    // in the segment
    if (l <= ss && se <= r)
    {
        return tree[si];
    }
 
    // If a part of this segment
    // overlaps with the given range
    int mid = getMid(ss, se);
    int p1 = queryPowerfulUtil(2 * si + 1,
                               ss, mid, l,
                               r);
    int p2 = queryPowerfulUtil(2 * si + 2,
                                  mid + 1,
                                 se, l, r);
    return (p1 + p2);
}
 
static void queryPowerful(int n, int l, int r)
{
    System.out.printf("Number of Powerful numbers " +
                      "between %d to %d = %d\n", l, r,
                      queryPowerfulUtil(0, 0, n - 1,
                                        l, r));
}
 
static void updateValue(int n, int ind, int val)
{
     
    // If val is a Powerful number
    // we will update 1 in tree
    if (powerful[val])
        updateValueUtil(0, 0, n - 1,
                        ind, 1);
    else
        updateValueUtil(0, 0, n - 1,
                        ind, 0);
}
 
static void precomputePowerful()
{
    Arrays.fill(powerful, false);
     
    // Computing all Powerful
    // numbers till MAX
    for(int i = 1; i <= MAX; i++)
    {
         
        // If the number is
        // Powerful make
        // powerful[i] = true
        if (isPowerful(i))
            powerful[i] = true;
    }
}
 
// Driver Code
public static void main(String[] args)
{
     
    // Precompute all the powerful
    // numbers till MAX
    precomputePowerful();
 
    // Input array
    int input[] = { 4, 5, 18, 27, 40, 144 };
     
    // Size of Input array
    int n = input.length;
 
    // Build the array.
    BuildArray(input, n);
     
    // Build segment tree from
    // given array
    constructSTUtil(0, 0, n - 1);
 
    // Query 1: Query(L = 0, R = 3)
    int l = 0, r = 3;
    queryPowerful(n, l, r);
 
    // Query 2: Update(i = 1, x = 9),
    // i.e Update input[i] to x
    int i = 1;
    int val = 9;
    updateValue(n, i, val);
 
    // Query 3: Query(L = 0, R = 3)
    queryPowerful(n, l, r);
}
}
 
// This code is contributed by amal kumar choubey


C#
// C# program to find the number
// of Powerful numbers in subarray
// using segment tree
using System;
class GFG{
 
static readonly int MAX = 100000;
 
// Size of segment tree = 2^{log(MAX)+1}
static int []tree = new int[3 * MAX];
static int []arr = new int[MAX];
static bool []powerful = new bool[MAX + 1];
 
// Function to check if the
// number is powerful
static bool isPowerful(int n)
{
     
    // First divide the number
    // repeatedly by 2
    while (n % 2 == 0)
    {
        int power = 0;
        while (n % 2 == 0)
        {
            n /= 2;
            power++;
        }
 
        // If only 2^1 divides
        // n (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // If n is not a power of 2 then
    // this loop will execute
    // repeat above process
    for(int factor = 3;
            factor <= Math.Sqrt(n);
            factor += 2)
    {
         
        // Find highest power of
        // "factor" that divides n
        int power = 0;
        while (n % factor == 0)
        {
            n = n / factor;
            power++;
        }
 
        // If only factor^1 divides n
        // (not higher powers),
        // then return false
        if (power == 1)
            return false;
    }
 
    // n must be 1 now if it is not
    // a prime numenr. Since prime
    // numbers are not powerful,
    // we return false if n is not 1.
    return (n == 1);
}
 
// Function to build the array
static void BuildArray(int []input, int n)
{
    for(int i = 0; i < n; i++)
    {
         
        // Check if input[i] is
        // a Powerful number or not
        if (powerful[input[i]])
            arr[i] = 1;
 
        else
            arr[i] = 0;
    }
    return;
}
 
// 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 -. 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[index]
*/
static void constructSTUtil(int si, int ss,
                            int se)
{
    if (ss == se)
    {
         
        // If there is one element
        // in array
        tree[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements,
    // then recur for left and right subtrees
    // and store the sum of the two
    // values in this node
    else
    {
        int mid = getMid(ss, se);
         
        constructSTUtil(2 * si + 1,
                        ss, mid);
         
        constructSTUtil(2 * si + 2,
                        mid + 1, se);
         
        tree[si] = tree[2 * si + 1] +
                   tree[2 * si + 2];
    }
}
 
/* A recursive function to update the
nodes which have the given index
in their range.
 
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[index]
 
ind -. Index of array to be updated
 
val -. The new value to be updated
 
*/
static void updateValueUtil(int si, int ss, int se,
                            int idx, int val)
{
     
    // Leaf node
    if (ss == se)
    {
        tree[si] = tree[si] - arr[idx] + val;
        arr[idx] = val;
    }
    else
    {
        int mid = getMid(ss, se);
         
        // If idx is in the left child,
        // recurse on the left child
        if (ss <= idx && idx <= mid)
            updateValueUtil(2 * si + 1, ss,
                            mid, idx, val);
 
        // If idx is in the right child,
        // recurse on the right child
        else
            updateValueUtil(2 * si + 2, mid + 1,
                            se, idx, val);
 
        // Internal node will have the sum
        // of both of its children
        tree[si] = tree[2 * si + 1] +
                   tree[2 * si + 2];
    }
}
 
/* A recursive function to get the number
of Powerful numbers in a given
range of array indexes
 
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[index]
l & r -. Starting and ending indexes of
        query range
 
*/
static int queryPowerfulUtil(int si, int ss,
                             int se, int l, int r)
{
     
    // If segment of this node is
    // outside the given range
    if (r < ss || se < l)
    {
        return 0;
    }
     
    // If segment of this node is a part
    // of given range, then return the
    // number of composites
    // in the segment
    if (l <= ss && se <= r)
    {
        return tree[si];
    }
 
    // If a part of this segment
    // overlaps with the given range
    int mid = getMid(ss, se);
    int p1 = queryPowerfulUtil(2 * si + 1,
                               ss, mid, l,
                               r);
    int p2 = queryPowerfulUtil(2 * si + 2,
                                  mid + 1,
                                 se, l, r);
    return (p1 + p2);
}
 
static void queryPowerful(int n, int l, int r)
{
    Console.WriteLine("Number of Powerful numbers " +
                      "between " + l +" to "+r+" = "+
                      queryPowerfulUtil(0, 0, n - 1,
                                        l, r));
}
 
static void updateValue(int n, int ind, int val)
{
     
    // If val is a Powerful number
    // we will update 1 in tree
    if (powerful[val])
        updateValueUtil(0, 0, n - 1,
                        ind, 1);
    else
        updateValueUtil(0, 0, n - 1,
                        ind, 0);
}
 
static void precomputePowerful()
{
    
    for(int i = 0; i <= MAX; i++)
        powerful[i] = false;
     
    // Computing all Powerful
    // numbers till MAX
    for(int i = 1; i <= MAX; i++)
    {
         
        // If the number is
        // Powerful make
        // powerful[i] = true
        if (isPowerful(i))
            powerful[i] = true;
    }
}
 
// Driver Code
public static void Main(String[] args)
{
     
    // Precompute all the powerful
    // numbers till MAX
    precomputePowerful();
 
    // Input array
    int []input = { 4, 5, 18, 27, 40, 144 };
     
    // Size of Input array
    int n = input.Length;
 
    // Build the array.
    BuildArray(input, n);
     
    // Build segment tree from
    // given array
    constructSTUtil(0, 0, n - 1);
 
    // Query 1: Query(L = 0, R = 3)
    int l = 0, r = 3;
    queryPowerful(n, l, r);
 
    // Query 2: Update(i = 1, x = 9),
    // i.e Update input[i] to x
    int i = 1;
    int val = 9;
    updateValue(n, i, val);
 
    // Query 3: Query(L = 0, R = 3)
    queryPowerful(n, l, r);
}
}
 
// This code is contributed by Rohit_ranjan


输出:
Number of Powerful numbers between 0 to 3 = 2
Number of Powerful numbers between 0 to 3 = 3



时间复杂度:每个查询O(logN)