Given an empty set initially and a number of queries on it, each possibly of the following types:
- Insert – Insert a new element ‘x’.
- Delete – Delete an existing element ‘x’.
- Median – Print the median element of the numbers currently in the set
Example:
Input : Insert 1
Insert 4
Insert 7
Median
Output : The first three queries
should insert 1, 4 and 7
into an empty set. The
fourth query should return
4 (median of 1, 4, 7).
For expository purpose, we assume the following, but these assumptions are not the limitations of the method discussed here:
1. At any instance, all elements are distinct, that is, none of them occurs more than once.
2. The ‘Median’ query is made only when there are odd number of elements in the set.( We will need to make two queries on our segment tree, in case of even numbers )
3. The elements in the set range from 1 to +10^6.
Method 1 (Naive)
In naive implementation, we can do first two queries in O(1), but the last query in O(max_elem), where max_elem is the maximum element of all times (including deleted elements).
Let us assume an array count[] (of size 10^6 + 1) to maintain the count of each element in the subset. Following are simple and self explanatory algorithms for the 3 queries:
Insert x query:
count[x]++;
if (x > max_elem)
max_elem = x;
n++;
Delete x query:
if (count[x] > 0)
count[x]--;
n--;
Median query:
sum = 0;
i = 0;
while( sum <= n / 2 )
{
i++;
sum += count[i];
}
median = i;
return median;
Illustration of array count[], representing the set {1, 4, 7, 8, 9}, the median element is ‘7’:
The ‘Median’ query intends to find the (n + 1)/2 th ‘1’ in the array, in this case, 3rd ‘1’; now we do the same using a segment tree.
Method 2(Using Segment Tree)
We make a segment tree to store sum of intervals, where an interval [a, b] represents the number of elements present in the set, currently, in the range [a, b]. For example, if we consider the above example, query( 3, 7) returns 2, query(4, 4) returns 1, query(5, 5) returns 0.
Insert and delete queries are simple and both can be implemented using function update(int x, int diff) (adds ‘diff’ at index ‘x’)
Algorithm
// adds ‘diff’ at index ‘x’
update(node, a, b, x, diff)
// If leaf node
If a == b and a == x
segmentTree[node] += diff
// If non-leaf node and x lies in its range
If x is in [a, b]
// Update children recursively
update(2*node, a, (a + b)/2, x, diff)
update(2*node + 1, (a + b)/2 + 1, b, x, diff)
// Update node
segmentTree[node] = segmentTree[2 * node] +
segmentTree[2 * node + 1]
The above recursive function runs in O( log( max_elem ) ) ( in this case max_elem is 10^6) and used for both insertion and deletion with the following calls:
- Insert ‘x’ is done using update(1, 0, 10^6, x, 1). Note that root of tree is passed, start index is passed as 0 and end index as 10^6 so that all ranges that have x are updated.
- Delete ‘x’ is done using update(1, 0, 10^6, x, -1). Note that root of tree is passed, start index is passed as 0 and end index as 10^6 so that all ranges that have x are updated.
Now, the function to find the index with kth ‘1’, where ‘k’ in this case will always be (n + 1) / 2, this is going to work a lot like binary search, you can think of it as a recursive binary search function on a segment tree.
Let’s take an example to understand, our set currently has elements { 1, 4, 7, 8, 9 }, and hence is represented by the following segment tree.
If we are at a non-leaf node, we are sure that it has both children, we see if the left child has more or equal number of one’s as ‘k’, if yes, we are sure our index lies in the left subtree, otherwise, if left subtree has less number of 1’s than k, then we are sure that our index lies in the right subtree. We do this recursively to reach our index and from there, we return it.
Algorithm
1.findKth(node, a, b, k)
2. If a != b
3. If segmentTree[ 2 * node ] >= k
4. return findKth(2*node, a, (a + b)/2, k)
5. else
6. return findKth(2*node + 1, (a + b)/2 + 1,
b, k - segmentTree[ 2 * node ])
7. else
8. return a
The above recursive function runs in O( log(max_elem) ).
C++
#include<bits/stdc++.h>
#define maxn 3000005
#define max_elem 1000000
using namespace std;
int segmentTree[maxn];
void update( int node, int a, int b, int x, int diff)
{
if (a == b && a == x )
{
segmentTree[node] += diff;
return ;
}
if (x >= a && x <= b)
{
update(node*2, a, (a + b)/2, x, diff);
update(node*2 + 1, (a + b)/2 + 1, b, x, diff);
segmentTree[node] = segmentTree[node*2] +
segmentTree[node*2 + 1];
}
}
int findKth( int node, int a, int b, int k)
{
if (a != b)
{
if (segmentTree[node*2] >= k)
return findKth(node*2, a, (a + b)/2, k);
return findKth(node*2 + 1, (a + b)/2 + 1,
b, k - segmentTree[node*2]);
}
return (segmentTree[node])? a : -1;
}
void insert( int x)
{
update(1, 0, max_elem, x, 1);
}
void delete ( int x)
{
update(1, 0, max_elem, x, -1);
}
int median()
{
int k = (segmentTree[1] + 1) / 2;
return findKth(1, 0, max_elem, k);
}
int main()
{
insert(1);
insert(4);
insert(7);
cout << "Median for the set {1,4,7} = "
<< median() << endl;
insert(8);
insert(9);
cout << "Median for the set {1,4,7,8,9} = "
<< median() << endl;
delete (1);
delete (8);
cout << "Median for the set {4,7,9} = "
<< median() << endl;
return 0;
}
|
Java
import java.io.*;
class GFG{
public static int maxn = 3000005 ;
public static int max_elem = 1000000 ;
public static int [] segmentTree = new int [maxn];
public static void update( int node, int a, int b,
int x, int diff)
{
if (a == b && a == x )
{
segmentTree[node] += diff;
return ;
}
if (x >= a && x <= b)
{
update(node * 2 , a, (a + b) / 2 , x, diff);
update(node * 2 + 1 , (a + b) / 2 + 1 ,
b, x, diff);
segmentTree[node] = segmentTree[node * 2 ] +
segmentTree[node * 2 + 1 ];
}
}
public static int findKth( int node, int a,
int b, int k)
{
if (a != b)
{
if (segmentTree[node * 2 ] >= k)
{
return findKth(node * 2 , a, (a + b) / 2 , k);
}
return findKth(node * 2 + 1 , (a + b) / 2 + 1 ,
b, k - segmentTree[node * 2 ]);
}
return (segmentTree[node] != 0 ) ? a : - 1 ;
}
public static void insert( int x)
{
update( 1 , 0 , max_elem, x, 1 );
}
public static void delete( int x)
{
update( 1 , 0 , max_elem, x, - 1 );
}
public static int median()
{
int k = (segmentTree[ 1 ] + 1 ) / 2 ;
return findKth( 1 , 0 , max_elem, k);
}
public static void main(String[] args)
{
insert( 1 );
insert( 4 );
insert( 7 );
System.out.println( "Median for the set {1,4,7} = " +
median());
insert( 8 );
insert( 9 );
System.out.println( "Median for the set {1,4,7,8,9} = " +
median());
delete( 1 );
delete( 8 );
System.out.println( "Median for the set {4,7,9} = " +
median());
}
}
|
Python3
maxn = 3000005
max_elem = 1000000
segmentTree = [ 0 for i in range (maxn)]
def update(node, a, b, x, diff):
global segmentTree
if (a = = b and a = = x ):
segmentTree[node] + = diff
return
if (x > = a and x < = b):
update(node * 2 , a, (a + b) / / 2 , x, diff)
update(node * 2 + 1 , (a + b) / / 2 + 1 , b, x, diff)
segmentTree[node] = segmentTree[node * 2 ] + segmentTree[node * 2 + 1 ]
def findKth(node, a, b, k):
global segmentTree
if (a ! = b):
if (segmentTree[node * 2 ] > = k):
return findKth(node * 2 , a, (a + b) / / 2 , k)
return findKth(node * 2 + 1 , (a + b) / / 2 + 1 ,
b, k - segmentTree[node * 2 ])
return a if (segmentTree[node]) else - 1
def insert(x):
update( 1 , 0 , max_elem, x, 1 )
def delete(x):
update( 1 , 0 , max_elem, x, - 1 )
def median():
k = (segmentTree[ 1 ] + 1 ) / / 2
return findKth( 1 , 0 , max_elem, k)
if __name__ = = '__main__' :
insert( 1 )
insert( 4 )
insert( 7 )
print ( "Median for the set {1,4,7} =" ,median())
insert( 8 )
insert( 9 )
print ( "Median for the set {1,4,7,8,9} =" ,median())
delete( 1 )
delete( 8 )
print ( "Median for the set {4,7,9} =" ,median())
|
C#
using System;
class GFG{
public static int maxn = 3000005;
public static int max_elem = 1000000;
public static int [] segmentTree = new int [maxn];
public static void update( int node, int a,
int b, int x, int diff)
{
if (a == b && a == x)
{
segmentTree[node] += diff;
return ;
}
if (x >= a && x <= b)
{
update(node * 2, a, (a + b) / 2, x, diff);
update(node * 2 + 1, (a + b) / 2 + 1,
b, x, diff);
segmentTree[node] = segmentTree[node * 2] +
segmentTree[node * 2 + 1];
}
}
public static int findKth( int node, int a,
int b, int k)
{
if (a != b)
{
if (segmentTree[node * 2] >= k)
{
return findKth(node * 2, a,
(a + b) / 2, k);
}
return findKth(node * 2 + 1, (a + b) / 2 + 1,
b, k - segmentTree[node * 2]);
}
if (segmentTree[node] != 0)
{
return a;
}
else
{
return -1;
}
}
public static void insert( int x)
{
update(1, 0, max_elem, x, 1);
}
public static void delete( int x)
{
update(1, 0, max_elem, x, -1);
}
public static int median()
{
int k = (segmentTree[1] + 1) / 2;
return findKth(1, 0, max_elem, k);
}
static public void Main()
{
insert(1);
insert(4);
insert(7);
Console.WriteLine( "Median for the set {1,4,7} = " +
median());
insert(8);
insert(9);
Console.WriteLine( "Median for the set {1,4,7,8,9} = " +
median());
delete(1);
delete(8);
Console.WriteLine( "Median for the set {4,7,9} = " +
median());
}
}
|
Javascript
<script>
let maxn = 3000005;
let max_elem = 1000000;
let segmentTree = new Array(maxn);
for (let i=0;i<maxn;i++)
{
segmentTree[i]=0;
}
function update(node,a,b,x,diff)
{
if (a == b && a == x )
{
segmentTree[node] += diff;
return ;
}
if (x >= a && x <= b)
{
update(node * 2, a, Math.floor((a + b) / 2), x, diff);
update(node * 2 + 1, Math.floor((a + b) / 2) + 1,
b, x, diff);
segmentTree[node] = segmentTree[node * 2] +
segmentTree[node * 2 + 1];
}
}
function findKth(node,a,b,k)
{
if (a != b)
{
if (segmentTree[node * 2] >= k)
{
return findKth(node * 2, a, Math.floor((a + b) / 2), k);
}
return findKth(node * 2 + 1, Math.floor((a + b) / 2) + 1,
b, k - segmentTree[node * 2]);
}
return (segmentTree[node] != 0) ? a : -1;
}
function insert(x)
{
update(1, 0, max_elem, x, 1);
}
function delet(x)
{
update(1, 0, max_elem, x, -1);
}
function median()
{
let k = (segmentTree[1] + 1) / 2;
return findKth(1, 0, max_elem, k);
}
insert(1);
insert(4);
insert(7);
document.write( "Median for the set {1,4,7} = " +
median()+ "<br>" );
insert(8);
insert(9);
document.write( "Median for the set {1,4,7,8,9} = " +
median()+ "<br>" );
delet(1);
delet(8);
document.write( "Median for the set {4,7,9} = " +
median()+ "<br>" );
</script>
|
Output:
Median for the set {1,4,7} = 4
Median for the set {1,4,7,8,9} = 7
Median for the set {4,7,9} = 7
Conclusion:
All three queries run in O( log(max_elem) ), in this case max_elem = 10^6, so log(max_elem) is approximately equal to 20.
The segment tree uses O( max_elem ) space.
If the delete query wasn’t there, the problem could have also been done with a famous algorithm here.
Last Updated :
28 Sep, 2021
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...