📜  范围LCM查询

📅  最后修改于: 2021-04-17 09:25:05             🧑  作者: Mango

给定一个整数数组,请评估形式为LCM(l,r)的查询。可能有很多查询,因此可以有效地评估查询。

LCM (l, r) denotes the LCM of array elements
           that lie between the index l and r
           (inclusive of both indices) 

Mathematically, 
LCM(l, r) = LCM(arr[l],  arr[l+1] , ......... ,
                                  arr[r-1], arr[r])

例子:

Inputs : Array = {5, 7, 5, 2, 10, 12 ,11, 17, 14, 1, 44}
         Queries: LCM(2, 5), LCM(5, 10), LCM(0, 10)
Outputs: 60 15708 78540
Explanation : In the first query LCM(5, 2, 10, 12) = 60, 
              similarly in other queries.

一个幼稚的解决方案是遍历每个查询的数组,并使用来计算答案,
LCM(a,b)=(a * b)/ GCD(a,b)

但是,由于查询的数量可能很大,因此这种解决方案是不切实际的。

一个有效的解决方案是使用段树。回想一下,在这种情况下,不需要更新,我们可以构建一次树,然后可以反复使用树来回答查询。树中的每个节点都应存储该特定段的LCM值,我们可以使用与上述相同的公式来组合这些段。因此,我们可以有效地回答每个查询!

下面是相同的解决方案。

C++
// LCM of given range queries using Segment Tree
#include 
using namespace std;
  
#define MAX 1000
  
// allocate space for tree
int tree[4*MAX];
  
// declaring the array globally
int arr[MAX];
  
// Function to return gcd of a and b
int gcd(int a, int b)
{
    if (a == 0)
        return b;
    return gcd(b%a, a);
}
  
//utility function to find lcm
int lcm(int a, int b)
{
    return a*b/gcd(a,b);
}
  
// Function to build the segment tree
// Node starts beginning index of current subtree.
// start and end are indexes in arr[] which is global
void build(int node, int start, int end)
{
    // If there is only one element in current subarray
    if (start==end)
    {
        tree[node] = arr[start];
        return;
    }
  
    int mid = (start+end)/2;
  
    // build left and right segments
    build(2*node, start, mid);
    build(2*node+1, mid+1, end);
  
    // build the parent
    int left_lcm = tree[2*node];
    int right_lcm = tree[2*node+1];
  
    tree[node] = lcm(left_lcm, right_lcm);
}
  
// Function to make queries for array range )l, r).
// Node is index of root of current segment in segment
// tree (Note that indexes in segment tree begin with 1
// for simplicity).
// start and end are indexes of subarray covered by root
// of current segment.
int query(int node, int start, int end, int l, int r)
{
    // Completely outside the segment, returning
    // 1 will not affect the lcm;
    if (endr)
        return 1;
  
    // completely inside the segment
    if (l<=start && r>=end)
        return tree[node];
  
    // partially inside
    int mid = (start+end)/2;
    int left_lcm = query(2*node, start, mid, l, r);
    int right_lcm = query(2*node+1, mid+1, end, l, r);
    return lcm(left_lcm, right_lcm);
}
  
//driver function to check the above program
int main()
{
    //initialize the array
    arr[0] = 5;
    arr[1] = 7;
    arr[2] = 5;
    arr[3] = 2;
    arr[4] = 10;
    arr[5] = 12;
    arr[6] = 11;
    arr[7] = 17;
    arr[8] = 14;
    arr[9] = 1;
    arr[10] = 44;
  
    // build the segment tree
    build(1, 0, 10);
  
    // Now we can answer each query efficiently
  
    // Print LCM of (2, 5)
    cout << query(1, 0, 10, 2, 5) << endl;
  
    // Print LCM of (5, 10)
    cout << query(1, 0, 10, 5, 10) << endl;
  
    // Print LCM of (0, 10)
    cout << query(1, 0, 10, 0, 10) << endl;
  
    return 0;
}


Java
// LCM of given range queries 
// using Segment Tree 
  
class GFG 
{
  
    static final int MAX = 1000;
  
    // allocate space for tree 
    static int tree[] = new int[4 * MAX];
  
    // declaring the array globally 
    static int arr[] = new int[MAX];
  
    // Function to return gcd of a and b 
    static int gcd(int a, int b) {
        if (a == 0) {
            return b;
        }
        return gcd(b % a, a);
    }
  
    // utility function to find lcm 
    static int lcm(int a, int b) 
    {
        return a * b / gcd(a, b);
    }
  
    // Function to build the segment tree 
    // Node starts beginning index 
    // of current subtree. start and end
    // are indexes in arr[] which is global 
    static void build(int node, int start, int end) 
    {
          
        // If there is only one element
        // in current subarray 
        if (start == end) 
        {
            tree[node] = arr[start];
            return;
        }
  
        int mid = (start + end) / 2;
  
        // build left and right segments 
        build(2 * node, start, mid);
        build(2 * node + 1, mid + 1, end);
  
        // build the parent 
        int left_lcm = tree[2 * node];
        int right_lcm = tree[2 * node + 1];
  
        tree[node] = lcm(left_lcm, right_lcm);
    }
  
    // Function to make queries for 
    // array range )l, r). Node is index
    // of root of current segment in segment 
    // tree (Note that indexes in segment  
    // tree begin with 1 for simplicity). 
    // start and end are indexes of subarray 
    // covered by root of current segment. 
    static int query(int node, int start,
                    int end, int l, int r) 
    {
          
        // Completely outside the segment, returning 
        // 1 will not affect the lcm; 
        if (end < l || start > r) 
        {
            return 1;
        }
  
        // completely inside the segment 
        if (l <= start && r >= end)
        {
            return tree[node];
        }
  
        // partially inside 
        int mid = (start + end) / 2;
        int left_lcm = query(2 * node, start, mid, l, r);
        int right_lcm = query(2 * node + 1, mid + 1, end, l, r);
        return lcm(left_lcm, right_lcm);
    }
  
    // Driver code
    public static void main(String[] args) 
    {
  
        //initialize the array 
        arr[0] = 5;
        arr[1] = 7;
        arr[2] = 5;
        arr[3] = 2;
        arr[4] = 10;
        arr[5] = 12;
        arr[6] = 11;
        arr[7] = 17;
        arr[8] = 14;
        arr[9] = 1;
        arr[10] = 44;
  
        // build the segment tree 
        build(1, 0, 10);
  
        // Now we can answer each query efficiently 
        // Print LCM of (2, 5) 
        System.out.println(query(1, 0, 10, 2, 5));
  
        // Print LCM of (5, 10) 
        System.out.println(query(1, 0, 10, 5, 10));
  
        // Print LCM of (0, 10) 
        System.out.println(query(1, 0, 10, 0, 10));
  
    }
}
  
// This code is contributed by 29AjayKumar


Python3
# LCM of given range queries using Segment Tree
MAX = 1000
  
# allocate space for tree
tree = [0] * (4 * MAX)
  
# declaring the array globally
arr = [0] * MAX
  
# Function to return gcd of a and b
def gcd(a: int, b: int):
    if a == 0:
        return b
    return gcd(b % a, a)
  
# utility function to find lcm
def lcm(a: int, b: int):
    return (a * b) // gcd(a, b)
  
# Function to build the segment tree
# Node starts beginning index of current subtree.
# start and end are indexes in arr[] which is global
def build(node: int, start: int, end: int):
  
    # If there is only one element 
    # in current subarray
    if start == end:
        tree[node] = arr[start]
        return
  
    mid = (start + end) // 2
  
    # build left and right segments
    build(2 * node, start, mid)
    build(2 * node + 1, mid + 1, end)
  
    # build the parent
    left_lcm = tree[2 * node]
    right_lcm = tree[2 * node + 1]
  
    tree[node] = lcm(left_lcm, right_lcm)
  
# Function to make queries for array range )l, r).
# Node is index of root of current segment in segment
# tree (Note that indexes in segment tree begin with 1
# for simplicity).
# start and end are indexes of subarray covered by root
# of current segment.
def query(node: int, start: int, 
           end: int, l: int, r: int):
  
    # Completely outside the segment, 
    # returning 1 will not affect the lcm;
    if end < l or start > r:
        return 1
  
    # completely inside the segment
    if l <= start and r >= end:
        return tree[node]
  
    # partially inside
    mid = (start + end) // 2
    left_lcm = query(2 * node, start, mid, l, r)
    right_lcm = query(2 * node + 1, 
                      mid + 1, end, l, r)
    return lcm(left_lcm, right_lcm)
  
# Driver Code
if __name__ == "__main__":
  
    # initialize the array
    arr[0] = 5
    arr[1] = 7
    arr[2] = 5
    arr[3] = 2
    arr[4] = 10
    arr[5] = 12
    arr[6] = 11
    arr[7] = 17
    arr[8] = 14
    arr[9] = 1
    arr[10] = 44
  
    # build the segment tree
    build(1, 0, 10)
  
    # Now we can answer each query efficiently
  
    # Print LCM of (2, 5)
    print(query(1, 0, 10, 2, 5))
  
    # Print LCM of (5, 10)
    print(query(1, 0, 10, 5, 10))
  
    # Print LCM of (0, 10)
    print(query(1, 0, 10, 0, 10))
  
# This code is contributed by
# sanjeev2552


C#
// LCM of given range queries 
// using Segment Tree 
using System;
using System.Collections.Generic;
  
class GFG 
{
    static readonly int MAX = 1000;
  
    // allocate space for tree 
    static int []tree = new int[4 * MAX];
  
    // declaring the array globally 
    static int []arr = new int[MAX];
  
    // Function to return gcd of a and b 
    static int gcd(int a, int b) 
    {
        if (a == 0) 
        {
            return b;
        }
        return gcd(b % a, a);
    }
  
    // utility function to find lcm 
    static int lcm(int a, int b) 
    {
        return a * b / gcd(a, b);
    }
  
    // Function to build the segment tree 
    // Node starts beginning index 
    // of current subtree. start and end
    // are indexes in []arr which is global 
    static void build(int node, int start, int end) 
    {
          
        // If there is only one element
        // in current subarray 
        if (start == end) 
        {
            tree[node] = arr[start];
            return;
        }
  
        int mid = (start + end) / 2;
  
        // build left and right segments 
        build(2 * node, start, mid);
        build(2 * node + 1, mid + 1, end);
  
        // build the parent 
        int left_lcm = tree[2 * node];
        int right_lcm = tree[2 * node + 1];
  
        tree[node] = lcm(left_lcm, right_lcm);
    }
  
    // Function to make queries for 
    // array range )l, r). Node is index
    // of root of current segment in segment 
    // tree (Note that indexes in segment 
    // tree begin with 1 for simplicity). 
    // start and end are indexes of subarray 
    // covered by root of current segment. 
    static int query(int node, int start,
                     int end, int l, int r) 
    {
          
        // Completely outside the segment, 
        // returning 1 will not affect the lcm; 
        if (end < l || start > r) 
        {
            return 1;
        }
  
        // completely inside the segment 
        if (l <= start && r >= end)
        {
            return tree[node];
        }
  
        // partially inside 
        int mid = (start + end) / 2;
        int left_lcm = query(2 * node, start, mid, l, r);
        int right_lcm = query(2 * node + 1, 
                              mid + 1, end, l, r);
        return lcm(left_lcm, right_lcm);
    }
  
    // Driver code
    public static void Main(String[] args) 
    {
  
        // initialize the array 
        arr[0] = 5;
        arr[1] = 7;
        arr[2] = 5;
        arr[3] = 2;
        arr[4] = 10;
        arr[5] = 12;
        arr[6] = 11;
        arr[7] = 17;
        arr[8] = 14;
        arr[9] = 1;
        arr[10] = 44;
  
        // build the segment tree 
        build(1, 0, 10);
  
        // Now we can answer each query efficiently 
        // Print LCM of (2, 5) 
        Console.WriteLine(query(1, 0, 10, 2, 5));
  
        // Print LCM of (5, 10) 
        Console.WriteLine(query(1, 0, 10, 5, 10));
  
        // Print LCM of (0, 10) 
        Console.WriteLine(query(1, 0, 10, 0, 10));
    }
}
  
// This code is contributed by Rajput-Ji


输出:

60
15708
78540