给定一个由N个整数组成的数组,任务是对给定的数组执行以下两个操作:
query(L, R): Print the number of Powerful numbers in the subarray from L to R.
update(i, x) : update the value at index i to x, i.e arr[i] = x
如果对每个素数p,p 2也将其除,则数字N被称为有力数。
先决条件:强大的数字,段树
例子:
Input:
arr = {1, 12, 3, 8, 17, 9}
Query 1: query(L = 1, R = 4)
Query 2: update(i = 1, x = 9)
Query 3: query(L = 1, R = 4)
Output:
1
2
Explanation:
Query 1: Powerful numbers in range arr[1:4] is 8.
Query 2: Powerful numbers in range arr[1:4] after update operation is 9 and 8.
方法:
由于我们需要处理点更新和范围查询,因此我们将使用细分树来解决该问题。
- 我们将预先计算所有强大的数,直到arr [i]可以取最大值,例如MAX 。
此操作的时间复杂度为O(MAX * sqrt(MAX)) - 构建段树:
- 可以使用段树将问题简化为子数组总和。
- 现在,我们可以构建段树,其中叶节点将表示1 (当数字是有效数字时)或0 (当数字不是有效数字时)。所有内部节点都将具有其两个子节点的总和。
- 点更新:
- 要更新元素,我们需要查看元素所在的间隔,并在左边或右边的子元素上相应地递归。如果要更新的元素是强大的数字,则我们将叶子更新为1,否则更新为0。
- 范围查询:
- 每当我们收到从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)