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

📅  最后修改于: 2021-04-17 11:53:12             🧑  作者: 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]阶乘

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

例子:

简单方法:一种简单的解决方案是运行从L到的阶乘元素r和计算总和的环路在给定范围内的第三查询(预先计算)。对于第二个查询,要更新值,只需将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 ,请将其从集合中删除,因为即使在进行任何下一次更新查询之后,它也不会影响我们的总和查询答案。
  • 对于第二种类型的更新操作,请使用给定值调用更新函数。同样,给定值<40 ,将要替换的元素的索引插入到集合中,如果给定值≥40 ,则将其从集合中删除,因为它在求和查询中不重要。
  • 对于第三种类型的总和查询,只需执行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