📜  段树中节点的逐级交替GCD和LCM

📅  最后修改于: 2021-04-17 13:10:44             🧑  作者: Mango

Levelwise GCD / LCM交替段树是一个段树,因此在每个级别上,操作GCD和LCM都是交替的。在1级换句话说,左,右子树由GCD操作即父节点=左子右GCD儿童和2级左结合在一起
和右子树通过LCM操作合并在一起,即父节点=左子节点LCM右子节点
这种类型的细分树具有以下类型的结构:

操作(GCD)和(LCM)指示执行了哪个操作来合并子节点
给定N个叶节点,任务是构建这样的段树并打印根节点。
例子:

Input : arr[] = { 5, 4, 8, 10, 6 }
Output : Value at Root Node = 2
Explanation : The image given above shows the 
segment tree corresponding to the given
set leaf nodes.

先决条件:段树
在此分段树中,我们进行两项操作: -GCD和LCM
现在,与递归传递给子树的信息一起,由于这些操作逐级交替,因此也传递了与要在该级进行的操作有关的信息。重要的是要注意,父节点在调用其左子节点和右子节点时,会将相同的操作信息传递给两个子节点,因为它们在同一级别上。
让我们分别用0和1表示两个操作,即GCD和LCM。然后,如果在级别i上执行GCD操作,则将在级别(i +1)下执行LCM操作。因此,如果级别i的运算为0,则级别(i + 1)的运算为1。

Operation at Level (i + 1) = ! (Operation at Level i)
where,
Operation at Level i ∊ {0, 1}

对图像的仔细分析表明,如果树的高度均匀,则根节点是其左,右子级的LCM操作的结果,否则是GCD操作的结果。

CPP
#include 
using namespace std;
 
// Recursive function to return gcd of a and b
int gcd(int a, int b)
{
    // Everything divides 0
    if (a == 0 || b == 0)
       return 0;
  
    // base case
    if (a == b)
        return a;
  
    // a is greater
    if (a > b)
        return gcd(a-b, b);
    return gcd(a, b-a);
}
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
void STconstructUtill(int arr[], int ss, int se, int* st,
                                          int si, int op)
{
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, !op);
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
        // GCD operation
        st[si] = __gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
        // LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                   (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
}
 
/* Function to construct segment tree from given array.
This function allocates memory for segment tree and
calls STconstructUtil() to fill the allocated memory */
int* STconstruct(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // allocate memory
    int* st = new int[max_size];
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
int main()
{
    int arr[] = { 5, 4, 8, 10, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Build segment tree
    int* st = STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    int rootIndex = 0;
 
    cout << "Value at Root Node = " << st[rootIndex];
 
    return 0;
}


Java
import java.io.*;
import java.util.*;
class GFG
{
 
  // Recursive function to return gcd of a and b
  static int gcd(int a, int b)
  {
 
    // Everything divides 0 
    if (a == 0 || b == 0)
      return 0;
 
    // base case
    if (a == b)
      return a;
 
    // a is greater
    if (a > b)
      return gcd(a - b, b);
    return gcd(a, b - a);
  }
 
  // A utility function to get the middle index from
  // corner indexes.
  static int getMid(int s, int e) { return s + (e - s) / 2; }
  static void STconstructUtill(int[] arr, int ss,
                               int se, int[] st, 
                               int si, boolean op)
  {
 
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se)
    {
      st[si] = arr[ss];
      return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, !op);
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if(op == true)
    {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else
    {
 
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and 
    calls STconstructUtil() to fill the allocated memory */
  static int[] STconstruct(int arr[], int n)
  {
 
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(Math.ceil((Math.log(n)/Math.log(2))));
 
    // maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // allocate memory
    int[] st = new int[max_size];
    boolean opAtRoot;
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    if(x % 2 == 0)
    {
      opAtRoot = false;
    }
    else
    {
      opAtRoot = true;
    }
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
  }
 
  // Driver code
  public static void main (String[] args)
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.length;
 
    // Build segment tree
    int[] st=STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    System.out.println("Value at Root Node = " + st[0]);
  }
}
 
// This code is contributed by avanitrachhadiya2155


Python3
from math import ceil,floor,log
 
# Recursive function to return gcd of a and b
def gcd(a, b):
 
    # Everything divides 0
    if (a == 0 or b == 0):
        return 0
 
    # base case
    if (a == b):
        return a
 
    # a is greater
    if (a > b):
        return gcd(a - b, b)
    return gcd(a, b - a)
 
# A utility function to get the middle index from
# corner indexes.
def getMid(s, e):
    return s + (e - s) // 2
 
def STconstructUtill(arr, ss, se, st, si, op):
     
    # If there is one element in array, store it in
    # current node of segment tree and return
    if (ss == se):
        st[si] = arr[ss]
        return
 
    # If there are more than one elements, then recur
    # for left and right subtrees and store the sum of
    # values in this node
    mid = getMid(ss, se)
 
    # Build the left and the right subtrees by using
    # the fact that operation at level (i + 1) = !
    # (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, not op)
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, not op)
 
    # merge the left and right subtrees by checking
    # the operation to be carried. If operation = 1,
    # then do GCD else LCM
    if (op == 1):
         
        # GCD operation
        st[si] =gcd(st[2 * si + 1], st[2 * si + 2])
    else :
         
        # LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) //(gcd(st[2 * si + 1], st[2 * si + 2]))
#
# /* Function to construct segment tree from given array.
# This function allocates memory for segment tree and
# calls STconstructUtil() to fill the allocated memory */
def STconstruct(arr, n):
    # Allocate memory for segment tree
 
    # Height of segment tree
    x = ceil(log(n, 2))
 
    # maximum size of segment tree
    max_size = 2 *pow(2, x) - 1
 
    # allocate memory
    st = [0]*max_size
 
    # operation = 1(GCD) if Height of tree is
    # even else it is 0(LCM) for the root node
    if (x % 2 == 0):
        opAtRoot = 0
    else:
        opAtRoot = 1
 
    # Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot)
 
    # Return the constructed segment tree
    return st
 
# Driver code
if __name__ == '__main__':
    arr = [5, 4, 8, 10, 6]
    n = len(arr)
 
    # Build segment tree
    st = STconstruct(arr, n)
 
    # 0-based indexing in segment tree
    rootIndex = 0
 
    print("Value at Root Node = ",st[rootIndex])
     
# This code is contributed by mohit kumar 29


C#
using System;
 
class GFG
{
 
  // Recursive function to return gcd of a and b
  static int gcd(int a, int b)
  {
 
    // Everything divides 0 
    if (a == 0 || b == 0)
      return 0;
 
    // base case
    if (a == b)
      return a;
 
    // a is greater
    if (a > b)
      return gcd(a - b, b);
    return gcd(a, b - a);
  }
 
  // A utility function to get the middle index from
  // corner indexes.
  static int getMid(int s, int e) { return s + (e - s) / 2; }
  static void STconstructUtill(int[] arr, int ss,
                               int se, int[] st,
                               int si, bool op)
  {
 
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se)
    {
      st[si] = arr[ss];
      return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, !op);
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if(op == true)
    {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else
    {
 
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and 
    calls STconstructUtil() to fill the allocated memory */
  static int[] STconstruct(int[] arr, int n)
  {
 
    // Allocate memory for segment tree
    // Height of segment tree
    int x = (int)(Math.Ceiling((Math.Log(n)/Math.Log(2))));
 
    // maximum size of segment tree
    int max_size = 2 * (int)Math.Pow(2, x) - 1;
 
    // allocate memory
    int[] st = new int[max_size];
    bool opAtRoot;
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    if(x % 2 == 0)
    {
      opAtRoot = false;
    }
    else
    {
      opAtRoot = true;
    }
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
  }
 
  // Driver code
  static public void Main ()
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.Length;
 
    // Build segment tree
    int[] st=STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    Console.WriteLine("Value at Root Node = " + st[0]);
  }
}
 
//  This code is contributed by rag2127


Javascript


CPP
#include 
using namespace std;
 
// Recursive function to return gcd of a and b
int gcd(int a, int b)
{
    // Everything divides 0
    if (a == 0 || b == 0)
       return 0;
  
    // base case
    if (a == b)
        return a;
  
    // a is greater
    if (a > b)
        return gcd(a-b, b);
    return gcd(a, b-a);
}
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
void STconstructUtill(int arr[], int ss, int se, int* st,
                                          int si, int op)
{
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, !op);
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
        // GCD operation
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
        // LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                  (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
}
 
void updateUtil(int* st, int ss, int se, int ind, int val,
                                            int si, int op)
{
    // Base Case: If the input index lies outside
    // this segment
    if (ind < ss || ind > se)
        return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == ind) {
        st[si] = val;
        return;
    }
 
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    updateUtil(st, ss, mid, ind, val, 2 * si + 1, !op);
    updateUtil(st, mid + 1, se, ind, val, 2 * si + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
 
        // GCD operation
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
 
        // LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                  (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
}
 
void update(int arr[], int* st, int n, int ind, int val)
{
    // Check for erroneous input index
    if (ind < 0 || ind > n - 1) {
        printf("Invalid Input");
        return;
    }
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[ind] = val;
 
    // Update the values of nodes in segment tree
    updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
}
 
/* Function to construct segment tree from given array.
This function allocates memory for segment tree and
calls STconstructUtil() to fill the allocated memory */
int* STconstruct(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // allocate memory
    int* st = new int[max_size];
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
int main()
{
    int arr[] = { 5, 4, 8, 10, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Build segment tree
    int* st = STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    int rootIndex = 0;
 
    cout << "Old Value at Root Node = " <<
                             st[rootIndex] << endl;
 
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
 
    cout << "New Value at Root Node = " <<
                             st[rootIndex] << endl;
 
    return 0;
}


Java
import java.util.*;
public class GFG
{
  // Recursive function to return gcd of a and b
  static int gcd(int a, int b)
  {
 
    // Everything divides 0
    if (a == 0 || b == 0)
      return 0;
 
    // base case
    if (a == b)
      return a;
 
    // a is greater
    if (a > b)
      return gcd(a - b, b);
    return gcd(a, b - a);
  }
 
  // A utility function to get the middle index from
  // corner indexes.
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
 
  static void STconstructUtill(int[] arr, int ss, int se, int[] st,
                               int si, int op)
  {
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se)
    {
      st[si] = arr[ss];
      return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    if(op != 0)
    {
      STconstructUtill(arr, ss, mid, st,
                       si * 2 + 1, 0);
    }
    else{
      STconstructUtill(arr, ss, mid, st,
                       si * 2 + 1, 1);
    }
 
    if(op != 0)
    {
      STconstructUtill(arr, mid + 1, se, st,
                       si * 2 + 2, 0);
    }
    else{
      STconstructUtill(arr, mid + 1, se, st,
                       si * 2 + 2, 1);
    }
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1)
    {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1],
                   st[2 * si + 2]);
    }
    else {
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  static void updateUtil(int[] st, int ss, int se,
                         int ind, int val,
                         int si, int op)
  {
 
    // Base Case: If the input index lies outside
    // this segment
    if (ind < ss || ind > se)
      return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == ind)
    {
      st[si] = val;
      return;
    }
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    if(op != 0)
    {
      updateUtil(st, ss, mid, ind,
                 val, 2 * si + 1, 0);
    }
    else{
      updateUtil(st, ss, mid, ind,
                 val, 2 * si + 1, 1);
    }
 
    if(op != 0)
    {
      updateUtil(st, mid + 1, se, ind,
                 val, 2 * si + 2, 0);
    }
    else{
      updateUtil(st, mid + 1, se, ind,
                 val, 2 * si + 2, 1);
    }
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
 
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  static void update(int[] arr, int[] st,
                     int n, int ind, int val)
  {
    // Check for erroneous input index
    if (ind < 0 || ind > n - 1)
    {
      System.out.print("Invalid Input");
      return;
    }
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[ind] = val;
 
    // Update the values of nodes in segment tree
    updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
  }
 
  /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and
    calls STconstructUtil() to fill the allocated memory */
  static int[] STconstruct(int[] arr, int n)
  {
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));
 
    // maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // allocate memory
    int[] st = new int[max_size];
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
  }
 
  // Driver code
  public static void main(String[] args)
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.length;
 
    // Build segment tree
    int[] st = STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    int rootIndex = 0;
 
    System.out.println("Old Value at Root Node = " + st[rootIndex]);
 
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
    System.out.println("New Value at Root Node = " + st[rootIndex]);
  }
}
 
// This code is contributed by divyeshrabadiya07.


C#
using System;
class GFG
{
     
    // Recursive function to return gcd of a and b
    static int gcd(int a, int b)
    {
       
        // Everything divides 0
        if (a == 0 || b == 0)
           return 0;
       
        // base case
        if (a == b)
            return a;
       
        // a is greater
        if (a > b)
            return gcd(a - b, b);
        return gcd(a, b - a);
    }
     
    // A utility function to get the middle index from
    // corner indexes.
    static int getMid(int s, int e)
    {
        return s + (e - s) / 2;
    }
      
    static void STconstructUtill(int[] arr, int ss, int se, int[] st,
                                              int si, int op)
    {
        // If there is one element in array, store it in
        // current node of segment tree and return
        if (ss == se)
        {
            st[si] = arr[ss];
            return;
        }
      
        // If there are more than one elements, then recur
        // for left and right subtrees and store the sum of
        // values in this node
        int mid = getMid(ss, se);
      
        // Build the left and the right subtrees by using
        // the fact that operation at level (i + 1) = !
        // (operation at level i)
        if(op != 0)
        {
            STconstructUtill(arr, ss, mid, st,
                             si * 2 + 1, 0);
        }
        else{
            STconstructUtill(arr, ss, mid, st,
                             si * 2 + 1, 1);
        }
         
        if(op != 0)
        {
            STconstructUtill(arr, mid + 1, se, st,
                             si * 2 + 2, 0);
        }
        else{
            STconstructUtill(arr, mid + 1, se, st,
                             si * 2 + 2, 1);
        }
      
        // merge the left and right subtrees by checking
        // the operation to be carried. If operation = 1,
        // then do GCD else LCM
        if (op == 1)
        {
           
            // GCD operation
            st[si] = gcd(st[2 * si + 1],
                         st[2 * si + 2]);
        }
        else {
            // LCM operation
            st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                      (gcd(st[2 * si + 1], st[2 * si + 2]));
        }
    }
      
    static void updateUtil(int[] st, int ss, int se,
                           int ind, int val,
                           int si, int op)
    {
       
        // Base Case: If the input index lies outside
        // this segment
        if (ind < ss || ind > se)
            return;
      
        // If the input index is in range of this node,
        // then update the value of the node and its
        // children
      
        // leaf node
        if (ss == se && ss == ind)
        {
            st[si] = val;
            return;
        }
        int mid = getMid(ss, se);
      
        // Update the left and the right subtrees by
        // using the fact that operation at level
        // (i + 1) = ! (operation at level i)
        if(op != 0)
        {
            updateUtil(st, ss, mid, ind,
                       val, 2 * si + 1, 0);
        }
        else{
            updateUtil(st, ss, mid, ind,
                       val, 2 * si + 1, 1);
        }
         
        if(op != 0)
        {
            updateUtil(st, mid + 1, se, ind,
                       val, 2 * si + 2, 0);
        }
        else{
            updateUtil(st, mid + 1, se, ind,
                       val, 2 * si + 2, 1);
        }
      
        // merge the left and right subtrees by checking
        // the operation to be carried. If operation = 1,
        // then do GCD else LCM
        if (op == 1) {
      
            // GCD operation
            st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
        }
        else {
      
            // LCM operation
            st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                      (gcd(st[2 * si + 1], st[2 * si + 2]));
        }
    }
      
    static void update(int[] arr, int[] st,
                       int n, int ind, int val)
    {
        // Check for erroneous input index
        if (ind < 0 || ind > n - 1)
        {
            Console.Write("Invalid Input");
            return;
        }
      
        // Height of segment tree
        int x = (int)(Math.Ceiling(Math.Log(n, 2)));
      
        // operation = 1(GCD) if Height of tree is
        // even else it is 0(LCM) for the root node
        int opAtRoot = (x % 2 == 0 ? 0 : 1);
      
        arr[ind] = val;
      
        // Update the values of nodes in segment tree
        updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
    }
      
    /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and
    calls STconstructUtil() to fill the allocated memory */
    static int[] STconstruct(int[] arr, int n)
    {
        // Allocate memory for segment tree
      
        // Height of segment tree
        int x = (int)(Math.Ceiling(Math.Log(n, 2)));
      
        // maximum size of segment tree
        int max_size = 2 * (int)Math.Pow(2, x) - 1;
      
        // allocate memory
        int[] st = new int[max_size];
      
        // operation = 1(GCD) if Height of tree is
        // even else it is 0(LCM) for the root node
        int opAtRoot = (x % 2 == 0 ? 0 : 1);
      
        // Fill the allocated memory st
        STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
      
        // Return the constructed segment tree
        return st;
    }
 
  // Driver code
  static void Main()
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.Length;
  
    // Build segment tree
    int[] st = STconstruct(arr, n);
  
    // 0-based indexing in segment tree
    int rootIndex = 0;
  
    Console.WriteLine("Old Value at Root Node = " + st[rootIndex]);
  
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
    Console.WriteLine("New Value at Root Node = " + st[rootIndex]);
  }
}
 
// This code is contributed by divyesh072019.


Javascript


输出:

Value at Root Node = 2

树的构造时间复杂度为O(n),因为总共有2 * n-1个节点,并且每个节点的值us都被一次计算出来。
现在要执行点更新,即用给定的索引和值更新值,可以通过遍历树到叶节点并执行更新来完成。
返回到根节点时,我们通过传递要在每个级别执行的操作并存储将其操作应用于其左子项和右子项的值并将结果存储到来再次构建类似于build()函数的树。该节点。
执行更新后,请考虑以下细分树,
arr [2] = 7
现在,更新后的细分树如下所示:

在此,黑色的节点表示已对其进行更新的事实。

CPP

#include 
using namespace std;
 
// Recursive function to return gcd of a and b
int gcd(int a, int b)
{
    // Everything divides 0
    if (a == 0 || b == 0)
       return 0;
  
    // base case
    if (a == b)
        return a;
  
    // a is greater
    if (a > b)
        return gcd(a-b, b);
    return gcd(a, b-a);
}
 
// A utility function to get the middle index from
// corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
void STconstructUtill(int arr[], int ss, int se, int* st,
                                          int si, int op)
{
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se) {
        st[si] = arr[ss];
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    STconstructUtill(arr, ss, mid, st, si * 2 + 1, !op);
    STconstructUtill(arr, mid + 1, se, st, si * 2 + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
        // GCD operation
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
        // LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                  (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
}
 
void updateUtil(int* st, int ss, int se, int ind, int val,
                                            int si, int op)
{
    // Base Case: If the input index lies outside
    // this segment
    if (ind < ss || ind > se)
        return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == ind) {
        st[si] = val;
        return;
    }
 
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    updateUtil(st, ss, mid, ind, val, 2 * si + 1, !op);
    updateUtil(st, mid + 1, se, ind, val, 2 * si + 2, !op);
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
 
        // GCD operation
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
 
        // LCM operation
        st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                  (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
}
 
void update(int arr[], int* st, int n, int ind, int val)
{
    // Check for erroneous input index
    if (ind < 0 || ind > n - 1) {
        printf("Invalid Input");
        return;
    }
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[ind] = val;
 
    // Update the values of nodes in segment tree
    updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
}
 
/* Function to construct segment tree from given array.
This function allocates memory for segment tree and
calls STconstructUtil() to fill the allocated memory */
int* STconstruct(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // allocate memory
    int* st = new int[max_size];
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
}
 
int main()
{
    int arr[] = { 5, 4, 8, 10, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Build segment tree
    int* st = STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    int rootIndex = 0;
 
    cout << "Old Value at Root Node = " <<
                             st[rootIndex] << endl;
 
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
 
    cout << "New Value at Root Node = " <<
                             st[rootIndex] << endl;
 
    return 0;
}

Java

import java.util.*;
public class GFG
{
  // Recursive function to return gcd of a and b
  static int gcd(int a, int b)
  {
 
    // Everything divides 0
    if (a == 0 || b == 0)
      return 0;
 
    // base case
    if (a == b)
      return a;
 
    // a is greater
    if (a > b)
      return gcd(a - b, b);
    return gcd(a, b - a);
  }
 
  // A utility function to get the middle index from
  // corner indexes.
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
 
  static void STconstructUtill(int[] arr, int ss, int se, int[] st,
                               int si, int op)
  {
    // If there is one element in array, store it in
    // current node of segment tree and return
    if (ss == se)
    {
      st[si] = arr[ss];
      return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the sum of
    // values in this node
    int mid = getMid(ss, se);
 
    // Build the left and the right subtrees by using
    // the fact that operation at level (i + 1) = !
    // (operation at level i)
    if(op != 0)
    {
      STconstructUtill(arr, ss, mid, st,
                       si * 2 + 1, 0);
    }
    else{
      STconstructUtill(arr, ss, mid, st,
                       si * 2 + 1, 1);
    }
 
    if(op != 0)
    {
      STconstructUtill(arr, mid + 1, se, st,
                       si * 2 + 2, 0);
    }
    else{
      STconstructUtill(arr, mid + 1, se, st,
                       si * 2 + 2, 1);
    }
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1)
    {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1],
                   st[2 * si + 2]);
    }
    else {
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  static void updateUtil(int[] st, int ss, int se,
                         int ind, int val,
                         int si, int op)
  {
 
    // Base Case: If the input index lies outside
    // this segment
    if (ind < ss || ind > se)
      return;
 
    // If the input index is in range of this node,
    // then update the value of the node and its
    // children
 
    // leaf node
    if (ss == se && ss == ind)
    {
      st[si] = val;
      return;
    }
    int mid = getMid(ss, se);
 
    // Update the left and the right subtrees by
    // using the fact that operation at level
    // (i + 1) = ! (operation at level i)
    if(op != 0)
    {
      updateUtil(st, ss, mid, ind,
                 val, 2 * si + 1, 0);
    }
    else{
      updateUtil(st, ss, mid, ind,
                 val, 2 * si + 1, 1);
    }
 
    if(op != 0)
    {
      updateUtil(st, mid + 1, se, ind,
                 val, 2 * si + 2, 0);
    }
    else{
      updateUtil(st, mid + 1, se, ind,
                 val, 2 * si + 2, 1);
    }
 
    // merge the left and right subtrees by checking
    // the operation to be carried. If operation = 1,
    // then do GCD else LCM
    if (op == 1) {
 
      // GCD operation
      st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }
    else {
 
      // LCM operation
      st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
        (gcd(st[2 * si + 1], st[2 * si + 2]));
    }
  }
 
  static void update(int[] arr, int[] st,
                     int n, int ind, int val)
  {
    // Check for erroneous input index
    if (ind < 0 || ind > n - 1)
    {
      System.out.print("Invalid Input");
      return;
    }
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    arr[ind] = val;
 
    // Update the values of nodes in segment tree
    updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
  }
 
  /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and
    calls STconstructUtil() to fill the allocated memory */
  static int[] STconstruct(int[] arr, int n)
  {
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));
 
    // maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // allocate memory
    int[] st = new int[max_size];
 
    // operation = 1(GCD) if Height of tree is
    // even else it is 0(LCM) for the root node
    int opAtRoot = (x % 2 == 0 ? 0 : 1);
 
    // Fill the allocated memory st
    STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
 
    // Return the constructed segment tree
    return st;
  }
 
  // Driver code
  public static void main(String[] args)
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.length;
 
    // Build segment tree
    int[] st = STconstruct(arr, n);
 
    // 0-based indexing in segment tree
    int rootIndex = 0;
 
    System.out.println("Old Value at Root Node = " + st[rootIndex]);
 
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
    System.out.println("New Value at Root Node = " + st[rootIndex]);
  }
}
 
// This code is contributed by divyeshrabadiya07.

C#

using System;
class GFG
{
     
    // Recursive function to return gcd of a and b
    static int gcd(int a, int b)
    {
       
        // Everything divides 0
        if (a == 0 || b == 0)
           return 0;
       
        // base case
        if (a == b)
            return a;
       
        // a is greater
        if (a > b)
            return gcd(a - b, b);
        return gcd(a, b - a);
    }
     
    // A utility function to get the middle index from
    // corner indexes.
    static int getMid(int s, int e)
    {
        return s + (e - s) / 2;
    }
      
    static void STconstructUtill(int[] arr, int ss, int se, int[] st,
                                              int si, int op)
    {
        // If there is one element in array, store it in
        // current node of segment tree and return
        if (ss == se)
        {
            st[si] = arr[ss];
            return;
        }
      
        // If there are more than one elements, then recur
        // for left and right subtrees and store the sum of
        // values in this node
        int mid = getMid(ss, se);
      
        // Build the left and the right subtrees by using
        // the fact that operation at level (i + 1) = !
        // (operation at level i)
        if(op != 0)
        {
            STconstructUtill(arr, ss, mid, st,
                             si * 2 + 1, 0);
        }
        else{
            STconstructUtill(arr, ss, mid, st,
                             si * 2 + 1, 1);
        }
         
        if(op != 0)
        {
            STconstructUtill(arr, mid + 1, se, st,
                             si * 2 + 2, 0);
        }
        else{
            STconstructUtill(arr, mid + 1, se, st,
                             si * 2 + 2, 1);
        }
      
        // merge the left and right subtrees by checking
        // the operation to be carried. If operation = 1,
        // then do GCD else LCM
        if (op == 1)
        {
           
            // GCD operation
            st[si] = gcd(st[2 * si + 1],
                         st[2 * si + 2]);
        }
        else {
            // LCM operation
            st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                      (gcd(st[2 * si + 1], st[2 * si + 2]));
        }
    }
      
    static void updateUtil(int[] st, int ss, int se,
                           int ind, int val,
                           int si, int op)
    {
       
        // Base Case: If the input index lies outside
        // this segment
        if (ind < ss || ind > se)
            return;
      
        // If the input index is in range of this node,
        // then update the value of the node and its
        // children
      
        // leaf node
        if (ss == se && ss == ind)
        {
            st[si] = val;
            return;
        }
        int mid = getMid(ss, se);
      
        // Update the left and the right subtrees by
        // using the fact that operation at level
        // (i + 1) = ! (operation at level i)
        if(op != 0)
        {
            updateUtil(st, ss, mid, ind,
                       val, 2 * si + 1, 0);
        }
        else{
            updateUtil(st, ss, mid, ind,
                       val, 2 * si + 1, 1);
        }
         
        if(op != 0)
        {
            updateUtil(st, mid + 1, se, ind,
                       val, 2 * si + 2, 0);
        }
        else{
            updateUtil(st, mid + 1, se, ind,
                       val, 2 * si + 2, 1);
        }
      
        // merge the left and right subtrees by checking
        // the operation to be carried. If operation = 1,
        // then do GCD else LCM
        if (op == 1) {
      
            // GCD operation
            st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
        }
        else {
      
            // LCM operation
            st[si] = (st[2 * si + 1] * st[2 * si + 2]) /
                      (gcd(st[2 * si + 1], st[2 * si + 2]));
        }
    }
      
    static void update(int[] arr, int[] st,
                       int n, int ind, int val)
    {
        // Check for erroneous input index
        if (ind < 0 || ind > n - 1)
        {
            Console.Write("Invalid Input");
            return;
        }
      
        // Height of segment tree
        int x = (int)(Math.Ceiling(Math.Log(n, 2)));
      
        // operation = 1(GCD) if Height of tree is
        // even else it is 0(LCM) for the root node
        int opAtRoot = (x % 2 == 0 ? 0 : 1);
      
        arr[ind] = val;
      
        // Update the values of nodes in segment tree
        updateUtil(st, 0, n - 1, ind, val, 0, opAtRoot);
    }
      
    /* Function to construct segment tree from given array.
    This function allocates memory for segment tree and
    calls STconstructUtil() to fill the allocated memory */
    static int[] STconstruct(int[] arr, int n)
    {
        // Allocate memory for segment tree
      
        // Height of segment tree
        int x = (int)(Math.Ceiling(Math.Log(n, 2)));
      
        // maximum size of segment tree
        int max_size = 2 * (int)Math.Pow(2, x) - 1;
      
        // allocate memory
        int[] st = new int[max_size];
      
        // operation = 1(GCD) if Height of tree is
        // even else it is 0(LCM) for the root node
        int opAtRoot = (x % 2 == 0 ? 0 : 1);
      
        // Fill the allocated memory st
        STconstructUtill(arr, 0, n - 1, st, 0, opAtRoot);
      
        // Return the constructed segment tree
        return st;
    }
 
  // Driver code
  static void Main()
  {
    int[] arr = { 5, 4, 8, 10, 6 };
    int n = arr.Length;
  
    // Build segment tree
    int[] st = STconstruct(arr, n);
  
    // 0-based indexing in segment tree
    int rootIndex = 0;
  
    Console.WriteLine("Old Value at Root Node = " + st[rootIndex]);
  
    // perform update arr[2] = 7
    update(arr, st, n, 2, 7);
    Console.WriteLine("New Value at Root Node = " + st[rootIndex]);
  }
}
 
// This code is contributed by divyesh072019.

Java脚本


输出:

Old Value at Root Node = 2
New Value at Root Node = 1

更新的时间复杂度也是O(Logn)。为了更新叶值,在每个级别处理一个节点,并且级别数为O(Logn)。