/**
(a)
|SORT(A,p,r)
| m <- (p + r) / 2
| x <- MEDIAN(A,p,r)
| PARTITION(A,p,r,x)
| SORT(A,p,m-1)
| SORT(A,m+1,r)
|[]
Justification:
The algorithm works as following: I put the median on the correct position and then, i do the same to the two halves.
Thus, in the end I will get all possible medians in their correct position, and this means the array is sorted.
Time complexity: T(n) = 2*T(n/2) + O(N) => O(NlogN)
(b)
|SELECT(A,p,r,nth) /// returns the elemen which is on the n'th position in the array
| m <- (p + r) / 2
| x <- MEDIAN(A,p,r)
| IF m = nth THEN RETURN x
| IF m < nth THEN RETURN SELECT(A,m+1,r,nth)
| RETURN SELECT(A,p,m-1,nth)
|[]
Justification:
The algorithm works as following: I search the interval [p,r] such that n'th element is it's middle. Thus, if n'th is current middle, i return it,
otherwise, if nth is bigger than my middle, i search the middle in the right half, otherwise in the left half.
Time complexity: T(n) = T(n/2) + O(N) => O(N)
(c)
To use a single MEDIAN call, we hope that it is the middle of the [p,q] interval.
If it is not, then we make it be the middle of the interval, by adding -INF at the beginning, or +INF at the ending of A.
This is also linear time complexity and works as following:
While nth > m, I add ininity at the end and update the new middle and the new q (length). This will shift the middle to the right until I reach the correct position
While nth < m, I add infinity at the beginning and update the new ending, the new middle and the new nth position. As nth position grows by 1 each time I add -INF and the middle grows by 1 only after two steps, nth will reach the middle.
Then, we just apply MEDIAN.
Time complexity: the complexity of median. However, this has to be implemented using the partitioning and either randomized pivot, either buckets of 5, the complexity is O(N).
For further details, check my C++ implementations.
*/
#include <bits/stdc++.h>
#define Nmax 3666013
using namespace std;
int N,K;
vector<int> A;
/// This API will partition vector V according to the boundaries [li,lf] and the value X
int Partition(vector<int> &V,int li,int lf,int X){
for(int i = li ; i <= lf; ++i){
if(V[i] == X)
swap(V[i],V[lf - 1]);
if(V[i] < X)
swap(V[li++],V[i]);
}
swap(V[lf - 1],V[li]);
return li;
}
/// This API will sort the elements using an O(N^2) sorting method
void Introsort(vector<int> &a,int li,int lf)
{
for(int i = li + 1; i <= lf; ++i)
{
int aux = a[i],k = i;
while(k > li && a[k-1] > aux)
{
a[k] = a[k-1];
--k;
}
a[k] = aux;
}
}
/// This API will return the element at pz'th position in a, in O(N) time.
int Med(vector<int> &a,int li,int lf,int pz)
{ /// O(N) time complexity, proved by T(N) = T(N/5) + T(7N/10) + bn
if(lf - li + 1 <= 5){
Introsort(a,li,lf);
return a[li + pz];
}
vector<int> aux1,aux2;
for(int i = li; i <= lf; ++i){
aux1.push_back(a[i]);
if((i-li) % 5 == 4){
Introsort(aux1,0,4);
aux2.push_back(aux1[2]);
aux1.clear();
}
}
if(aux1.size()){
Introsort(aux1,0,aux1.size()-1);
aux2.push_back( aux1[(aux1.size() - 1) / 2 ]);
}
int val = Med(aux2,0,aux2.size() - 1, (aux2.size() - 1)/2);
int m = Partition(a,li,lf,val);
if(m == pz)
return a[m];
if(m > pz)
return Med(a,li,m + 1,pz);
return Med(a,m + 1,lf,pz - m - 1);
}
///This API implements MEDIAN'
int Median(vector<int> &a,int li, int lf)
{
int m = li + ((lf - li) >> 1);
int k = Med(a,li,lf, m);
return a[m];
}
///This API sorts the elements in O(NlogN) time
void NiceSort(vector<int> &a, int li,int lf)
{ /// T(n) = 2*T(n/2) + O(N) => O(NlogN)
if(li >= lf)
return;
int m = li + ((lf - li) >> 1);
int k = Med(a,li,lf, m);
NiceSort(a,li, m - 1);
NiceSort(a,m + 1, lf);
}
///This API selects the pz'th element in O(N) time
int Select(vector<int> &a, int li, int lf, int pz)
{ /// T(n) = T(n/2) + O(N) => O(N)
int m = li + ((lf - li) >> 1);
int k = Median(a,li,lf);
if(m == pz)
return a[m];
if(m > pz)
return Select(a,li,m - 1,pz);
return Select(a,m+1,lf,pz);
}
/// This API will select the pz'th element in O(N) time, with just a single call of median
int PaddedSelect(vector<int> &a, int li, int lf,int pz)
{
vector<int> New;
int m = li + ((lf - li) >> 1);
if(pz == m)
New = a;
else
if(pz > m){
New = a;
while(pz > m)
{
New.push_back(999999999);
++lf;
m = li + ((lf - li) >> 1);
}
}
else
{
while(pz < m)
{
New.push_back(-999999999);
++pz;
++lf;
m = li + ((lf - li) >> 1);
}
for(auto it : a)
New.push_back(it);
}
/// Done the paddings
Median(New,li,lf);
return New[lf/2];
}
void Read()
{
scanf("%d%d",&N,&K);
A.resize(N);
for(int i = 0; i < N; ++i)
scanf("%d",&A[i]);
}
void Print()
{
///NiceSort(A,0,N-1);
///printf("%d\n",Median(A,0,N-1));
///printf("%d\n",Select(A,0,N-1,K));
printf("%d\n",PaddedSelect(A,0,N-1,K-1));
///for(auto it : A)
/// printf("%d ",it);
}
int main()
{
freopen("sdo.in","r",stdin);
freopen("sdo.out","w",stdout);
Read();
Print();
return 0;
}