A Segment Tree is a data structure that allows answering range queries over an array effectively, while still being flexible enough to allow modifying the array. This includes finding the sum of consecutive array elements a[l…r], or finding the minimum element in a such a range in O(logn) time. Between answering such queries the Segment Tree allows modifying the array by replacing one element, or even change the elements of a whole subsegment (e.g. assigning all elements a[l…r] to any value, or adding a value to all element in the subsegment).
In general a Segment Tree is a very flexible data structure, and a huge number of problems can be solved with it. Additionally it is also possible to apply more complex operations and answer more complex queries (see Advanced versions of Segment Trees).
One important property of Segment Trees is, that they require only a linear amount of memory. The standard Segment Tree requires 4n vertices for working on an array of size n.
Query Results = O(logN), Updates = O(logN), Tree construction = O(N)
Left Child = 2*index, Right child = 2*index + 1
Question - 1
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
The update(i, val) function modifies nums by updating the element at index i to val.
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly.
classNumArray {// A TreeNode stores sum of a rangeint[] tree, nums;publicNumArray(int[] nums) {this.nums= nums; tree =newint[4*nums.length];if(nums.length==0)return;// O(N)buildTree(0,nums.length-1,1); }publicvoidbuildTree(int start,int end,int index) {if (start == end) { tree[index] = nums[start];return; }int mid = start + (end - start) /2;buildTree(start, mid,2* index);buildTree(mid +1, end,2* index +1); tree[index] = tree[2* index] + tree[2* index +1]; }publicvoidupdate(int i,int val) {// O(logN)update(0,nums.length-1,1, i, val); }publicvoidupdate(int start,int end,int index,int updateIndex,int value) {if (start == end) {// At this point start == end == updateIndex nums[start] = tree[index] = value;return; }int mid = start + (end - start) /2;// Right callif (updateIndex > mid)update(mid +1, end,2* index +1, updateIndex, value);// Left callelseupdate(start, mid,2* index, updateIndex, value);// Reflect changes in parent node tree[index] = tree[2* index] + tree[2* index +1]; }publicintsumRange(int i,int j) {returnquery(0,nums.length-1,1, i, j); }publicintquery(int start,int end,int index,int L,int R) {// No overlapif (start > R || end < L)return0;// Complete overlapif (start >= L && end <= R)return tree[index];int mid = start + (end - start) /2;int leftSum =query(start, mid,2* index, L, R);int rightSum =query(mid +1, end,2* index +1, L, R);return leftSum + rightSum; }}
Question - 2
Given an array A of size N, there are two types of queries on this array.
1) l r: In this query you need to print the minimum in the sub-array A[l:r].
2) x y: In this query you need to update A[x]=y.
Examples:
Input: A={1, 3, 4, 2, 5}
Queries:
Type 1: L = 0, R = 2.
Type 2: i = 1, val = 6
Type 1: L = 0, R = 2.
Output:
1
1
classSolution {publicstaticvoidbuildTree(int[] arr,int[] tree,int start,int end,int index) {if (start == end) { tree[index] = arr[start];return; }int mid = start + (end - start) /2;buildTree(arr, tree, start, mid,2* index);buildTree(arr, tree, mid +1, end,2* index +1); tree[index] =Math.min(tree[2* index], tree[2* index +1]); }publicstaticintfindMin(int[] tree,int start,int end,int index,int L,int R) {if (start > R || end < L)returnInteger.MAX_VALUE;if (start >= L && end <= R)return tree[index];int mid = start + (end - start) /2;int leftMin =findMin(tree, start, mid,2* index, L, R);int rightMin =findMin(tree, mid +1, end,2* index +1, L, R);returnMath.min(leftMin, rightMin); } public static void updateElement(int[] arr, int[] tree, int start, int end, int index, int updateIndex, int value) {
if (start == end) { arr[start] = value; tree[index] = value;return; }int mid = start + (end - start) /2;if (updateIndex > mid)updateElement(arr, tree, mid + 1, end, 2 * index + 1, updateIndex, value);elseupdateElement(arr, tree, start, mid, 2 * index, updateIndex, value); tree[index] =Math.min(tree[2* index], tree[2* index +1]); }publicstaticvoidrangeQueries(int[] arr,int[][] queries) {int n =arr.length;int tree[] =newint[4* n];buildTree(arr, tree,0, n -1,1);for (int[] query : queries) {if (query[0] ==1)System.out.println(findMin(tree,0, n -1,1, query[1], query[2]));elseupdateElement(arr, tree,0, n -1,1, query[1], query[2]); } }}
Question - 3
Given an array of N positive integers. The task is to perform the following operations according to the type of query given.
1. Print the maximum pair product in a given range. [L-R]
2. Update Ai with some given value.
Examples:
Input: A={1, 3, 4, 2, 5}
Queries:
Type 1: L = 0, R = 2.
Type 2: i = 1, val = 6
Type 1: L = 0, R = 2.
Output:
12
24
For the query1, the maximum product in a range [0, 2] is 3*4 = 12.
For the query2, after an update, the array becomes [1, 6, 4, 2, 5]
For the query3, the maximum product in a range [0, 2] is 6*4 = 24.
You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows:
Query(x,y) = Max { a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y }.
Given M queries, your program must output the results of these queries.
classSolution {staticclassPair {int sum, mSum, bps, bss;// mSum -> max sum, bps -> best prefix sum, bss -> best suffix sumPair(int s,int m,int bps,int bss) {this.sum= s;this.mSum= m;this.bps= bps;this.bss= bss; } }publicstaticvoidbuildTree(int[] arr,Pair[] tree,int start,int end,int index) {if (start == end) { tree[index] =newPair(arr[start], arr[start], arr[start], arr[start]);return; }int mid = start + (end - start) /2;buildTree(arr, tree, start, mid,2* index);buildTree(arr, tree, mid +1, end,2* index +1); tree[index] =newPair(0,0,0,0); tree[index].sum= tree[2* index].sum+ tree[2* index +1].sum; tree[index].mSum=Math.max(Math.max(tree[2* index].mSum, tree[2* index +1].mSum),Math.max(Math.max(tree[2* index].sum+ tree[2* index +1].bps, tree[2* index].bss+ tree[2* index +1].sum), tree[2* index].bss+ tree[2* index +1].bps)); tree[index].bps=Math.max(tree[2* index].bps, tree[2* index].sum+ tree[2* index +1].bps); tree[index].bss=Math.max(tree[2* index +1].bss, tree[2* index].bss+ tree[2* index +1].sum); }publicstaticPairfindMaxProd(Pair[] tree,int start,int end,int index,int L,int R) {if (start > R || end < L)returnnewPair(-1000000,-1000000,-1000000,-1000000);if (start >= L && end <= R)return tree[index];int mid = start + (end - start) /2;Pair leftPair =findMaxProd(tree, start, mid,2* index, L, R);Pair rightPair =findMaxProd(tree, mid +1, end,2* index +1, L, R);Pair ans =newPair(0,0,0,0);ans.sum=leftPair.sum+rightPair.sum;ans.mSum=Math.max(Math.max(leftPair.mSum,rightPair.mSum),Math.max(Math.max(leftPair.sum+rightPair.bps,leftPair.bss+rightPair.sum),leftPair.bss+rightPair.bps));ans.bps=Math.max(leftPair.bps,leftPair.sum+rightPair.bps);ans.bss=Math.max(leftPair.bss+rightPair.sum,rightPair.bss);return ans; }publicstaticvoidrangeQueries(int[] arr,int[][] queries) {int n =arr.length;Pair tree[] =newPair[4* n];buildTree(arr, tree,0, n -1,1);for (int[] query : queries) {System.out.println(findMaxProd(tree,0, n -1,1, query[1], query[2]).mSum); } }}
Question - 5
Segment trees are extremely useful. In particular "Lazy Propagation" (i.e. see here, for example) allows one to compute sums over a range in O(lg(n)), and update ranges in O(lg(n)) as well. In this problem you will compute something much harder:
The sum of squares over a range with range updates of 2 types:
1) increment in a range
2) set all numbers the same in a range.
Input
There will be T (T <= 25) test cases in the input file. First line of the input contains two positive integers, N (N <= 100,000) and Q (Q <= 100,000).
The next line contains N integers, each at most 1000. Each of the next Q lines starts with a number, which indicates the type of operation:
2 st nd -- return the sum of the squares of the numbers with indices in [st, nd] {i.e., from st to nd inclusive} (1 <= st <= nd <= N).
1 st nd x -- add "x" to all numbers with indices in [st, nd] (1 <= st <= nd <= N, and -1,000 <= x <= 1,000).
0 st nd x -- set all numbers with indices in [st, nd] to "x" (1 <= st <= nd <= N, and -1,000 <= x <= 1,000).
Output
For each test case output the “Case <caseno>:” in the first line and from the second line output the sum of squares for each operation of type 2. Intermediate overflow will not occur with proper use of 64-bit signed integer.
classMain {staticclassTreeNode {int sum, sq_sum;TreeNode(int sum,int sq_sum) {this.sum= sum;this.sq_sum= sq_sum; } }staticclassLazyNode {// type : 0-> shows that no action is needed , 1-> shows that increment is needed,// 2-> replacement is neededint type, value;LazyNode(int type,int value) {this.type= type;this.value= value; } }publicstaticvoidhelper(TreeNode[] tree,LazyNode[] lazy,int start,int end,int index) {if (lazy[index].type==1) { tree[index].sq_sum+= (lazy[index].value* lazy[index].value* (end - start +1))+ (2* lazy[index].value* tree[index].sum); tree[index].sum+= lazy[index].value* (end - start +1);if (start != end) { lazy[2* index] =newLazyNode(1, lazy[2* index].value+ lazy[index].value); lazy[2* index +1] =newLazyNode(1, lazy[2* index +1].value+ lazy[index].value); } } else { tree[index].sq_sum= (end - start +1) * lazy[index].value* lazy[index].value; tree[index].sum= (end - start +1) * lazy[index].value;if (start != end) { lazy[2* index] =newLazyNode(2, lazy[index].value); lazy[2* index +1] =newLazyNode(2, lazy[index].value); } } lazy[index] =newLazyNode(0,0); }// building the lazy tree aswell with its default valuespublicstaticvoidbuild(int[] arr,TreeNode[] tree,LazyNode[] lazy,int start,int end,int index) {if (start == end) { tree[index] =newTreeNode(arr[start], arr[start] * arr[start]); lazy[index] =newLazyNode(0,0); // default valuesreturn; }int mid = (start + end) /2;build(arr, tree, lazy, start, mid,2* index);build(arr, tree, lazy, mid +1, end,2* index +1); tree[index] =newTreeNode(tree[2* index].sum+ tree[2* index +1].sum, tree[2* index].sq_sum+ tree[2* index +1].sq_sum); lazy[index] =newLazyNode(0,0);// default values }publicstaticvoidupdate(TreeNode[] tree,LazyNode[] lazy,int start,int end,int index,int L,int R,int value,int type) {if (lazy[index].type!=0)helper(tree, lazy, start, end, index);// no overlapif (start > R || end < L)return;// complete overlapif (start >= L && end <= R) {if (type ==1) { tree[index].sq_sum+=2* value * tree[index].sum+ (value * value * (end - start +1)); tree[index].sum+= value * (end - start +1);if (start != end) { lazy[2* index] =newLazyNode(1, lazy[2* index].value+ value); lazy[2* index +1] =newLazyNode(1, lazy[2* index +1].value+ value); } } else { tree[index].sq_sum= value * value * (end - start +1); tree[index].sum= value * (end - start +1);if (start != end) { lazy[2* index] =newLazyNode(2, value); lazy[2* index +1] =newLazyNode(2, value); } }return; }// partial overlapint mid = (start + end) /2;update(tree, lazy, start, mid,2* index, L, R, value, type);update(tree, lazy, mid +1, end,2* index +1, L, R, value, type); tree[index].sq_sum= tree[2* index].sq_sum+ tree[2* index +1].sq_sum; tree[index].sum= tree[2* index].sum+ tree[2* index +1].sum; }publicstaticTreeNodeprintQuery(TreeNode[] tree,LazyNode[] lazy,int start,int end,int index,int l,int r) {// no overlapif (start > r || end < l)returnnewTreeNode(0,0);if (lazy[index].type!=0)helper(tree, lazy, start, end, index);// complete overlapif (start >= l && end <= r)return tree[index];// partial overlapint mid = (start + end) /2;TreeNode leftAns =printQuery(tree, lazy, start, mid,2* index, l, r);TreeNode rightAns =printQuery(tree, lazy, mid +1, end,2* index +1, l, r);returnnewTreeNode(leftAns.sum+rightAns.sum,leftAns.sq_sum+rightAns.sq_sum); }publicstaticvoidmain(String[] args) {Scanner s =newScanner(System.in);int t =s.nextInt();for (int j =1; j <= t; j++) {int n =s.nextInt(), q =s.nextInt();int arr[] =newint[n];for (int i =0; i < n; i++) arr[i] =s.nextInt();TreeNode[] tree =newTreeNode[4* n];LazyNode[] lazy =newLazyNode[4* n];build(arr, tree, lazy,0, n -1,1);System.out.println("Case "+ j +":");while (q-->0) {int type =s.nextInt();int st =s.nextInt() -1;int nd =s.nextInt() -1;if (type ==2)System.out.println(printQuery(tree, lazy,0, n -1,1, st, nd).sq_sum);else {int x =s.nextInt();if (type ==1)update(tree, lazy,0, n -1,1, st, nd, x,1);elseupdate(tree, lazy,0, n -1,1, st, nd, x,2); } } }s.close(); }}
Question - 6
The fight for the best number in the globe is going to finally come to an end.The top two contenders for the best number are number 2 and number 3.It's the final the entire world was waiting for. Expectorates from all across the globe came to witness the breath taking finals.
The finals began in an astonishing way.A common problem was set for both of them which included both these number.The problem goes like this.
Given a binary string (that is a string consisting of only 0 and 1). They were supposed to perform two types of query on the string.
Type 0: Given two indices l and r.Print the value of the binary string from l to r modulo 3.
Type 1: Given an index l flip the value of that index if and only if the value at that index is 0.
The problem proved to be a really tough one for both of them.Hours passed by but neither of them could solve the problem.So both of them wants you to solve this problem and then you get the right to choose the best number in the globe.
Input:
The first line contains N denoting the length of the binary string .
The second line contains the N length binary string.Third line contains the integer Q indicating the number of queries to perform.
This is followed up by Q lines where each line contains a query.
Output:
For each query of Type 0 print the value modulo 3.
Constraints:
1<= N <=10^5
1<= Q <= 10^5
0 <= l <= r < N
Sample Input
5
10010
6
0 2 4
0 2 3
1 1
0 0 4
1 1
0 0 3
Sample Output
2
1
2
1
publicclassMain {staticint[] power =newint[100006], arr =newint[100006], tree =newint[300000];publicstaticvoidcalculatePowers() { power[0] =1;for (int i =1; i <100006; i++) power[i] = (power[i -1] *2) %3; }publicstaticvoidbuild(int index,int start,int end) {if (start == end) tree[index] = arr[start];else {int mid = start + (end - start) /2;build(2* index, start, mid);build(2* index +1, mid +1, end); tree[index] = (tree[2* index] * power[end - mid] + tree[2* index +1]) %3; } }publicstaticintquery(int index,int start,int end,int L,int R) {if (R< start || L > end)return0;if (L<= start && end <= R)return (tree[index] * power[R - end]) %3;int mid = (start + end) /2;int p1 =query(2* index, start, mid, L, R);int p2 =query(2* index +1, mid +1, end, L, R);return (p1 + p2) %3; }publicstaticvoidupdate(int index,int start,int end,int idx) {if (start == end) { tree[index] =1; arr[idx] =1; } else {int mid = (start + end) /2;if (start <= idx && mid >= idx)update(2* index, start, mid, idx);elseupdate(2* index +1, mid +1, end, idx); tree[index] = (tree[2* index] * power[end - mid] %3) + tree[2* index +1] %3; } }publicstaticvoidmain(String[] args) throwsException {Scanner in =newScanner(System.in);int n =in.nextInt();in.nextLine();char[] str =in.nextLine().toCharArray();calculatePowers();for (int i =0; i < n; i++) arr[i +1] = str[i] -'0';build(1,1, n);int q =in.nextInt();while (q-->0) {int t =in.nextInt();if (t ==0) {int l =in.nextInt(), r =in.nextInt();System.out.println(query(1,1, n, l +1, r +1)); } else {int x =in.nextInt();if (str[x] =='0') { str[x] ='1'; arr[x +1] =1;update(1,1, n, x +1); } } } }}
Question - 7
World is getting more evil and it's getting tougher to get into the Evil League of Evil. Since the legendary Bad Horse has retired, now you have to correctly answer the evil questions of Dr. Horrible, who has a PhD in horribleness (but not in Computer Science). You are given an array of N elements, which are initially all 0. After that you will be given C commands. They are -
0 p q v - you have to add v to all numbers in the range of p to q (inclusive), where p and q are two indexes of the array.
1 p q - output a line containing a single integer which is the sum of all the array elements between p and q (inclusive)
Input
In the first line you'll be given T, number of test cases.
Each test case will start with N (N <= 100 000) and C (C <= 100 000). After that you'll be given C commands in the format as mentioned above. 1 <= p, q <= N and 1 <= v <= 10^7.
classMajorityChecker {// A treeNode stores the majority element, with it's count// for a given rangestaticclassPair {int element, count;Pair(int element,int count) {this.element= element;this.count= count; } }int[] arr;Pair[] tree;// Map of Elements -> TreeSet of their indices// This is used for finding the occourence of an element in a given range in O(logN)Map<Integer,TreeSet<int[]>> map =newHashMap<>();publicMajorityChecker(int[] arr) {this.arr= arr; tree =newPair[4*arr.length];for (int i =0; i <arr.length; i++) {map.computeIfAbsent(arr[i], k ->newTreeSet<>((a, b) -> a[0] - b[0]));map.get(arr[i]).add(newint[] { i,map.get(arr[i]).size() }); }// NlogN processbuildTree(0,arr.length-1,1); }publicvoidbuildTree(int start,int end,int index) {if (start == end) { tree[index] =newPair(arr[start],1);return; }int mid = start + (end - start) /2;buildTree(start, mid,2* index);buildTree(mid +1, end,2* index +1);Pair left = tree[2* index], right = tree[2* index +1];int leftCount =0, rightCount =0;if (left.element!=-1) leftCount =map.get(left.element).floor(newint[] { end,0 })[1]-map.get(left.element).ceiling(newint[] { start,0 })[1] +1;if (right.element!=-1) rightCount =map.get(right.element).floor(newint[] { end,0 })[1]-map.get(right.element).ceiling(newint[] { start,0 })[1] +1;if (leftCount *2> end - start +1) tree[index] =newPair(left.element, leftCount);elseif (rightCount *2> end - start +1) tree[index] =newPair(right.element, rightCount);else tree[index] =newPair(-1,0); }publicintquery(int left,int right,int threshold) {// LogN*LogNPair majority =findMajority(0,arr.length-1,1, left, right);if (majority.count>= threshold)returnmajority.element;return-1; }publicPairfindMajority(int start,int end,int index,int L,int R) {if (start > R || end < L)returnnewPair(-1,0);if (start >= L && end <= R)return tree[index];int mid = start + (end - start) /2;Pair left =findMajority(start, mid,2* index, L, R);Pair right =findMajority(mid +1, end,2* index +1, L, R);Pair ans =newPair(-1,0);int leftCount =0, rightCount =0;int limit1 =Math.max(L, start), limit2 =Math.min(R, end);if (left.element!=-1) leftCount =map.get(left.element).floor(newint[] { limit2,0 })[1]-map.get(left.element).ceiling(newint[] { limit1,0 })[1] +1;if (right.element!=-1) rightCount =map.get(right.element).floor(newint[] { limit2,0 })[1]-map.get(right.element).ceiling(newint[] { limit1,0 })[1] +1;if (leftCount *2> limit2 - limit1 +1) ans =newPair(left.element, leftCount);elseif (rightCount *2> limit2 - limit1 +1) ans =newPair(right.element, rightCount);return ans; }}
Question - 9
Given a string num representing the digits of a very large integer and an integer k.
You are allowed to swap any two adjacent digits of the integer at mostk times.
Return the minimum integer you can obtain also as a string.
Example 1:
Input: num = "4321", k = 4
Output: "1342"
Explanation: The steps to obtain the minimum integer from 4321 with 4 adjacent swaps are shown.
Example 2:
Input: num = "100", k = 1
Output: "010"
Explanation: It's ok for the output to have leading zeros, but the input is guaranteed not to have any leading zeros.
Example 3:
Input: num = "36789", k = 1000
Output: "36789"
Explanation: We can keep the number without any swaps.
Example 4:
Input: num = "22", k = 22
Output: "22"
Example 5:
Input: num = "9438957234785635408", k = 23
Output: "0345989723478563548"
Constraints:
1 <= num.length <= 30000
num contains digits only and doesn't have leading zeros.
1 <= k <= 10^9
classSolution {publicStringminInteger(String num,int k) {// list stores the location of each digit.List<Queue<Integer>> list =newArrayList<>();for (int i =0; i <=9; ++i)list.add(newLinkedList<>());for (int i =0; i <num.length(); ++i)list.get(num.charAt(i) -'0').add(i);String ans ="";SegmentTree seg =newSegmentTree(num.length());for (int i =0; i <num.length(); ++i) {// At each location, try to place 0....9for (int digit =0; digit <=9; ++digit) {// is there any occurrence of digit left?if (list.get(digit).size() !=0) {// yes, there is a occurrence of digit at posInteger pos =list.get(digit).peek();// Since few numbers already shifted to left, this `pos` might be outdated.// we try to find how many number already got shifted that were to the left of// pos.int shift =seg.getCountLessThan(pos);// (pos - shift) is number of steps to make digit move from pos to i.if (pos - shift <= k) { k -= pos - shift;// Add pos to our segment tree.seg.add(pos);list.get(digit).remove(); ans += digit;break; } } } }return ans; }classSegmentTree {int[] nodes;int n;// Segment tree only stores the indices of shifted elementspublicSegmentTree(int max) { nodes =newint[4* (max)]; n = max; }publicvoidadd(int num) {addUtil(num,0, n,1); }privatevoidaddUtil(int num,int start,int end,int index) {if (num < start || num > end)return;if (start == end) { nodes[index]++;return; }int mid = (start + end) /2;addUtil(num, start, mid,2* index);addUtil(num, mid +1, end,2* index +1); nodes[index] = nodes[2* index] + nodes[2* index +1]; }// Essentialy it tells number of shifted numbers < num.publicintgetCountLessThan(int num) {returngetUtil(0, num,0, n,1); }privateintgetUtil(int leftLimit,int rightLimit,int start,int end,int index) {// No overlapif (rightLimit < start || leftLimit > end)return0;// Full overlapif (leftLimit <= start && rightLimit >= end)return nodes[index];// Partial overlapint mid = (start + end) /2;returngetUtil(leftLimit, rightLimit, start, mid,2* index)+getUtil(leftLimit, rightLimit, mid +1, end,2* index +1); } }}