// Java program to find number of fibonacci numbers
// in a subarray and performing updates
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
class GFG
{
static final int MAX = 1000;
// Function to create hash table
// to check Fibonacci numbers
static void createHash(Set<Integer> hash, int maxElement)
{
int prev = 0, curr = 1;
hash.add(prev);
hash.add(curr);
while (curr <= maxElement)
{
int temp = curr + prev;
hash.add(temp);
prev = curr;
curr = temp;
}
}
// A utility function to get the middle
// index from corner indexes.
static int getMid(int s, int e)
{
return s + (e - s) / 2;
}
// Recursive function to get the number
// of Fibonacci numbers in a given range
/*
* where st --> Pointer to segment tree index --> 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] qs & qe --> Starting and ending indexes of query range
*/
static int queryFibonacciUtil(int[] st, int ss, int se,
int qs, int qe, int index)
{
// If segment of this node is a part
// of given range, then return
// the number of Fibonacci numbers
// in the segment
if (qs <= ss && qe >= se)
return st[index];
// If segment of this node
// is outside the given range
if (se < qs || ss > qe)
return 0;
// If a part of this segment
// overlaps with the given range
int mid = getMid(ss, se);
return queryFibonacciUtil(st, ss, mid,
qs, qe, 2 * index + 1)
+ queryFibonacciUtil(st, mid + 1, se,
qs, qe, 2 * index + 2);
}
// Recursive function to update
// the nodes which have the given
// index in their range.
/*
* where st, si, ss and se are same as getSumUtil() i --> index of the element
* to be updated. This index is in input array. diff --> Value to be added to
* all nodes which have i in range
*/
static void updateValueUtil(int[] st, int ss,
int se, int i,
int diff, int si)
{
// Base Case:
// If the input index lies outside
// the range of this segment
if (i < ss || i > se)
return;
// If the input index is in range
// of this node, then update the value
// of the node and its children
st[si] = st[si] + diff;
if (se != ss)
{
int mid = getMid(ss, se);
updateValueUtil(st, ss, mid, i,
diff, 2 * si + 1);
updateValueUtil(st, mid + 1, se, i,
diff, 2 * si + 2);
}
}
// Function to update a value in the
// input array and segment tree.
// It uses updateValueUtil() to update
// the value in segment tree
static void updateValue(int arr[], int[] st, int n,
int i, int new_val, Set<Integer> hash)
{
// Check for erroneous input index
if (i < 0 || i > n - 1)
{
System.out.printf("Invalid Input");
return;
}
int diff = 0, oldValue;
oldValue = arr[i];
// Update the value in array
arr[i] = new_val;
// Case 1: Old and new values
// both are Fibonacci numbers
if (hash.contains(oldValue) &&
hash.contains(new_val))
return;
// Case 2: Old and new values
// both not Fibonacci numbers
if (!hash.contains(oldValue) &&
!hash.contains(new_val))
return;
// Case 3: Old value was Fibonacci,
// new value is non Fibonacci
if (hash.contains(oldValue) &&
!hash.contains(new_val))
{
diff = -1;
}
// Case 4: Old value was non Fibonacci,
// new_val is Fibonacci
if (!hash.contains(oldValue) &&
hash.contains(new_val))
{
diff = 1;
}
// Update the values of nodes in segment tree
updateValueUtil(st, 0, n - 1, i, diff, 0);
}
// Return number of Fibonacci numbers
// in range from index qs (query start)
// to qe (query end).
// It mainly uses queryFibonacciUtil()
static void queryFibonacci(int[] st, int n, int qs, int qe)
{
int FibonacciInRange = queryFibonacciUtil(st, 0,
n - 1, qs, qe, 0);
System.out.printf("Number of Fibonacci numbers in subarray from %d to %d = %d\n", qs, qe, FibonacciInRange);
}
// Recursive function that constructs
// Segment Tree for array[ss..se].
// si is index of current node
// in segment tree st
static int constructSTUtil(int arr[], int ss, int se,
int[] st, int si, Set<Integer> hash)
{
// If there is one element in array,
// check if it is Fibonacci number
// then store 1 in the segment tree
// else store 0 and return
if (ss == se)
{
// if arr[ss] is fibonacci number
if (hash.contains(arr[ss]))
st[si] = 1;
else
st[si] = 0;
return st[si];
}
// 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
int mid = getMid(ss, se);
st[si] = constructSTUtil(arr, ss, mid, st,
si * 2 + 1, hash)
+ constructSTUtil(arr, mid + 1, se,
st, si * 2 + 2, hash);
return st[si];
}
// Function to construct a segment tree from given array.
// This function allocates memory for segment tree and
// calls constructSTUtil() to fill the allocated memory
static int[] constructST(int arr[], int n, Set<Integer> hash)
{
// 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;
int[] st = new int[max_size];
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0, hash);
// Return the constructed segment tree
return st;
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 1, 2, 3, 4, 8, 9 };
int n = arr.length;
// find the largest node value in the array
int maxEle = Arrays.stream(arr).max().getAsInt();
// Creating a set containing all Fibonacci numbers
// upto the maximum data value in the array
Set<Integer> hash = new HashSet<>();
createHash(hash, maxEle);
// Build segment tree from given array
int[] st = constructST(arr, n, hash);
// Query 1: Query(start = 0, end = 4)
int start = 0;
int end = 4;
queryFibonacci(st, n, start, end);
// Query 2: Update(i = 3, x = 5),
// i.e Update a[i] to x
int i = 3;
int x = 5;
updateValue(arr, st, n, i, x, hash);
// uncomment to see array after update
// for(int i = 0; i < n; i++)
// cout << arr[i] << " ";
// Query 3: Query(start = 0, end = 4)
start = 0;
end = 4;
queryFibonacci(st, n, start, end);
}
}
// This code is contributed by sanjeev2552