📜  使用阶乘范围和更新总和查询

📅  最后修改于: 2021-09-16 10:51:03             🧑  作者: Mango

给定一个由N 个整数组成的数组arr[]和查询数量Q 。任务是回答三种类型的查询。

  1. 更新 [l, r] – 对于范围[l, r] 中的每个i 将arr[i]增加1
  2. 更新 [l, val] – 将arr[l]的值更改为val
  3. 查询 [l, r] – 计算arr[i]! % 10 9对于[l, r]范围内的所有i ,其中arr[i]!arr[i]阶乘

先决条件:二叉索引树 |段树

例子:

朴素的方法:一个简单的解决方案是运行从lr的循环,并为第三个查询计算给定范围内元素阶乘的总和(预先计算)。对于第二个查询,要更新值,只需将arr[i]替换为给定值,即arr[i] = val 。对于一种类型的查询,增加arr[i]的值,即arr[i] = arr[i] + 1

高效方法:仔细分析可以看出, 40!可以被 10 9整除,这意味着每个大于40 的数的阶乘都可以被10 9整除。因此,这在我们对第三个查询的答案中增加了零。这个想法是将每个查询和更新操作的时间复杂度降低到O(logN) 。使用二叉索引树 (BIT) 或段树。构造一个BIT[]数组,有查询和更新操作两个函数。

  • 现在,对于一种类型的每个更新操作,关键观察是给定范围内的数字最多可以更新为40 ,因为在那之后就无关紧要了,因为它将在我们的最终答案中添加零。我们将使用一个集合来存储那些小于 10 的数字的索引,并使用二进制搜索来查找更新查询的 l 索引并递增 l 索引,直到每个元素都在该更新查询的范围内更新。如果arr[i]在增加1后变得大于或等于40 ,请将其从集合中删除,因为即使在任何下一次更新查询之后它也不会影响我们对 sum 查询的答案。
  • 对于第二种类型的更新操作,调用给定值的更新函数。此外,给定值< 40 ,将要替换的元素的索引插入到集合中,如果给定值≥ 40 ,则将其从集合中删除,因为它在 sum 查询中不重要。
  • 对于第三种类型的和查询,只需执行query(r) – query(l – 1)

下面是上述方法的实现:

C++
// CPP program to calculate sum of
// factorials in an interval and update
// with two types of operations
#include 
using namespace std;
  
// Modulus
const int MOD = 1e9;
  
// Maximum size of input array
const int MAX = 100;
  
// Size for factorial array
const int SZ = 40;
  
int BIT[MAX + 1], fact[SZ + 1];
  
// structure for queries with members type,
// leftIndex, rightIndex of the query
struct queries {
    int type, l, r;
};
  
// function for updating the value
void update(int x, int val, int n)
{
    for (x; x <= n; x += x & -x)
        BIT[x] += val;
}
  
// function for calculating the required
// sum between two indexes
int sum(int x)
{
    int s = 0;
    for (x; x > 0; x -= x & -x)
        s += BIT[x];
    return s;
}
  
// function to return answer to queries
void answerQueries(int arr[], queries que[],
                   int n, int q)
{
    // Precomputing factorials
    fact[0] = 1;
    for (int i = 1; i < 41; i++)
        fact[i] = (fact[i - 1] * i) % MOD;
  
    // Declaring a Set
    set s;
    for (int i = 1; i < n; i++) {
  
        // inserting indexes of those
        // numbers which are lesser
        // than 40
        if (arr[i] < 40) {
            s.insert(i);
            update(i, fact[arr[i]], n);
        }
        else
            update(i, 0, n);
    }
  
    for (int i = 0; i < q; i++) {
  
        // update query of the 1st type
        if (que[i].type == 1) {
            while (true) {
  
                // find the left index of query in
                // the set using binary search
                auto it = s.lower_bound(que[i].l);
  
                // if it crosses the right index of
                // query or end of set, then break
                if (it == s.end() || *it > que[i].r)
                    break;
  
                que[i].l = *it;
                int val = arr[*it] + 1;
  
                // update the value of arr[i] to
                // its new value
                update(*it, fact[val] - fact[arr[*it]], n);
  
                arr[*it]++;
  
                // if updated value becomes greater
                // than or equal to 40 remove it from
                // the set
                if (arr[*it] >= 40)
                    s.erase(*it);
  
                // increment the index
                que[i].l++;
            }
        }
  
        // update query of the 2nd type
        else if (que[i].type == 2) {
            int idx = que[i].l;
            int val = que[i].r;
  
            // update the value to its new value
            update(idx, fact[val] - fact[arr[idx]], n);
  
            arr[idx] = val;
  
            // If the value is less than 40, insert
            // it into set, otherwise remove it
            if (val < 40)
                s.insert(idx);
            else
                s.erase(idx);
        }
  
        // sum query of the 3rd type
        else
            cout << (sum(que[i].r) - sum(que[i].l - 1))
                 << endl;
    }
}
  
// Driver Code to test above functions
int main()
{
    int q = 6;
  
    // input array using 1-based indexing
    int arr[] = { 0, 1, 2, 1, 4, 5 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    // declaring array of structure of type queries
    queries que[q + 1];
  
    que[0].type = 3, que[0].l = 1, que[0].r = 5;
    que[1].type = 1, que[1].l = 1, que[1].r = 3;
    que[2].type = 2, que[2].l = 2, que[2].r = 4;
    que[3].type = 3, que[3].l = 2, que[3].r = 4;
    que[4].type = 1, que[4].l = 2, que[4].r = 5;
    que[5].type = 3, que[5].l = 1, que[5].r = 5;
  
    // answer the Queries
    answerQueries(arr, que, n, q);
    return 0;
}


Python3
# Python3 program to calculate sum of
# factorials in an interval and update
# with two types of operations
from bisect import bisect_left as lower_bound
  
# Modulus
MOD = 1e9
  
# Maximum size of input array
MAX = 100
  
# Size for factorial array
SZ = 40
  
BIT = [0] * (MAX + 1)
fact = [0] * (SZ + 1)
  
# structure for queries with members type,
# leftIndex, rightIndex of the query
class queries:
    def __init__(self, tpe, l, r):
        self.type = tpe
        self.l = l
        self.r = r
  
# function for updating the value
def update(x, val, n):
    global BIT
    while x <= n:
        BIT[x] += val
        x += x & -x
  
# function for calculating the required
# sum between two indexes
def summ(x):
    global BIT
    s = 0
    while x > 0:
        s += BIT[x]
        x -= x & -x
    return s
  
# function to return answer to queries
def answerQueries(arr: list, que: list, 
                       n: int, q: int):
    global fact
  
    # Precomputing factorials
    fact[0] = 1
    for i in range(1, 41):
        fact[i] = int((fact[i - 1] * i) % MOD)
  
    # Declaring a Set
    s = set()
    for i in range(1, n):
  
        # inserting indexes of those
        # numbers which are lesser
        # than 40
        if arr[i] < 40:
            s.add(i)
            update(i, fact[arr[i]], n)
        else:
            update(i, 0, n)
  
    for i in range(q):
  
        # update query of the 1st type
        if que[i].type == 1:
            while True:
                s = list(s)
                s.sort()
  
                # find the left index of query in
                # the set using binary search
                it = lower_bound(s, que[i].l)
  
                # if it crosses the right index of
                # query or end of set, then break
                if it == len(s) or s[it] > que[i].r:
                    break
  
                que[i].l = s[it]
                val = arr[s[it]] + 1
  
                # update the value of arr[i] to
                # its new value
                update(s[it], fact[val] - 
                              fact[arr[s[it]]], n)
  
                arr[s[it]] += 1
  
                # if updated value becomes greater
                # than or equal to 40 remove it from
                # the set
                if arr[s[it]] >= 40:
                    s.remove(it)
  
                # increment the index
                que[i].l += 1
  
        # update query of the 2nd type
        elif que[i].type == 2:
            s = set(s)
            idx = que[i].l
            val = que[i].r
  
            # update the value to its new value
            update(idx, fact[val] - fact[arr[idx]], n)
  
            arr[idx] = val
  
            # If the value is less than 40, insert
            # it into set, otherwise remove it
            if val < 40:
                s.add(idx)
            else:
                s.remove(idx)
  
        # sum query of the 3rd type
        else:
            print((summ(que[i].r) - 
                   summ(que[i].l - 1)))
  
# Driver Code
if __name__ == "__main__":
  
    q = 6
  
    # input array using 1-based indexing
    arr = [0, 1, 2, 1, 4, 5]
    n = len(arr)
  
    # declaring array of structure of type queries
    que = [ queries(3, 1, 5),
            queries(1, 1, 3),
            queries(2, 2, 4),
            queries(3, 2, 4),
            queries(1, 2, 5),
            queries(3, 1, 5) ]
  
    # answer the Queries
    answerQueries(arr, que, n, q)
  
# This code is contributed by
# sanjeev2552


输出:
148
50
968

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程