Problem:
Score : 700 points

Problem Statement

We will define the median of a sequence b of length M, as follows:

Let b' be the sequence obtained by sorting b in non-decreasing order. Then, the value of the (M / 2 + 1)-th element of b' is the median of b. Here, / is integer division, rounding down.

For example, the median of (10, 30, 20) is 20; the median of (10, 30, 20, 40) is 30; the median of (10, 10, 10, 20, 30) is 10.

Snuke comes up with the following problem.

You are given a sequence a of length N.
For each pair (l, r) (1 \leq l \leq r \leq N), let m_{l, r} be the median of the contiguous subsequence (a_l, a_{l + 1}, ..., a_r) of a.
We will list m_{l, r} for all pairs (l, r) to create a new sequence m.
Find the median of m.

Constraints

1 \leq N \leq 10^5

a_i is an integer.

1 \leq a_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N
a_1 a_2 ... a_N

Output

Print the median of m.

Sample Input 1

3
10 30 20

Sample Output 1

30

The median of each contiguous subsequence of a is as follows:

The median of (10) is 10.

The median of (30) is 30.

The median of (20) is 20.

The median of (10, 30) is 30.

The median of (30, 20) is 30.

The median of (10, 30, 20) is 20.

Thus, m = (10, 30, 20, 30, 30, 20) and the median of m is 30.

Sample Input 2

1
10

Sample Output 2

10

Sample Input 3

10
5 9 5 9 8 9 3 5 4 3

Sample Output 3

8

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <iostream>
#include <vector>
#include <cstdio>
#include <sstream>
#include <map>
#include <string>
#include <algorithm>
#include <queue>
#include <cmath>
#include <functional>
#include <set>
#include <ctime>
#include <random>
#include <chrono>
#include <cassert>
#include <tuple>
#include <utility>
using namespace std;

namespace {
  using Integer = long long; //__int128;
  template<class T, class S> istream& operator >> (istream& is, pair<T,S>& p){return is >> p.first >> p.second;}
  template<class T> istream& operator >> (istream& is, vector<T>& vec){for(T& val: vec) is >> val; return is;}
  template<class T> istream& operator ,  (istream& is, T& val){ return is >> val;}
  template<class T, class S> ostream& operator << (ostream& os, const pair<T,S>& p){return os << p.first << " " << p.second;}
  template<class T> ostream& operator << (ostream& os, const vector<T>& vec){for(size_t i=0; i<vec.size(); i++) os << vec[i] << (i==vec.size()-1?"":" "); return os;}
  template<class T> ostream& operator ,  (ostream& os, const T& val){ return os << " " << val;}

  template<class H> void print(const H& head){ cout << head; }
  template<class H, class ... T> void print(const H& head, const T& ... tail){ cout << head << " "; print(tail...); }
  template<class ... T> void println(const T& ... values){ print(values...); cout << endl; }

  template<class H> void eprint(const H& head){ cerr << head; }
  template<class H, class ... T> void eprint(const H& head, const T& ... tail){ cerr << head << " "; eprint(tail...); }
  template<class ... T> void eprintln(const T& ... values){ eprint(values...); cerr << endl; }

  class range{ Integer start_, end_, step_; public: struct range_iterator{ Integer val, step_; range_iterator(Integer v, Integer step) : val(v), step_(step) {} Integer operator * (){return val;} void operator ++ (){val += step_;} bool operator != (range_iterator& x){return step_ > 0 ? val < x.val : val > x.val;} }; range(Integer len) : start_(0), end_(len), step_(1) {} range(Integer start, Integer end) : start_(start), end_(end), step_(1) {} range(Integer start, Integer end, Integer step) : start_(start), end_(end), step_(step) {} range_iterator begin(){ return range_iterator(start_, step_); } range_iterator   end(){ return range_iterator(  end_, step_); } };

  inline string operator "" _s (const char* str, size_t size){ return move(string(str)); }
  constexpr Integer my_pow(Integer x, Integer k, Integer z=1){return k==0 ? z : k==1 ? z*x : (k&1) ? my_pow(x*x,k>>1,z*x) : my_pow(x*x,k>>1,z);}
  constexpr Integer my_pow_mod(Integer x, Integer k, Integer M, Integer z=1){return k==0 ? z%M : k==1 ? z*x%M : (k&1) ? my_pow_mod(x*x%M,k>>1,M,z*x%M) : my_pow_mod(x*x%M,k>>1,M,z);}
  constexpr unsigned long long operator "" _ten (unsigned long long value){ return my_pow(10,value); }

  inline int k_bit(Integer x, int k){return (x>>k)&1;} //0-indexed

  mt19937 mt(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count());

  template<class T> string join(const vector<T>& v, const string& sep){ stringstream ss; for(size_t i=0; i<v.size(); i++){ if(i>0) ss << sep; ss << v[i]; } return ss.str(); }

  inline string operator * (string s, int k){ string ret; while(k){ if(k&1) ret += s; s += s; k >>= 1; } return ret; }
}
constexpr long long mod = 9_ten + 7;


template<class T = int>
class BinaryIndexedTree_1_indexed{
  void init(const vector<T> &A){
    for(int i=0; i<N; i++){
      add(i+1, A[i]);
    }
  }
  
public:
  vector<T> tree;
  int N;
  
  BinaryIndexedTree_1_indexed(const int n) : tree(n+1,0), N(n){
    
  }
  
  BinaryIndexedTree_1_indexed(const vector<T> &A) : tree(A.size()+1,0), N(A.size()){
    init(A);
  }

  //caution : position "i" must be 1-indexed
  void add(int i, const T x){
    while(i <= N){
      tree[i] += x;
      i += i & -i;
    }
  }

  //update node i to zero
  void to_zero(const int i){
    T val = get_at(i);
    add(i, -val);
  }

  //get sums [0,i]
  T get_sum(int i){
    T ret=0;
    while(i>0){
      ret += tree[i];
      i -= i & -i;
    }
    return ret;
  }

  //get sums [from,to]
  T get_sums_range(const int from, const int to){
    return get_sum(to) - get_sum(from-1);
  }

  //get at [i]
  T get_at(const int i){
    return get_sum(i) - get_sum(i-1);
  }

  int lower_bound(T val){
    if(val<=0) return 0;
    int x = 0;
    int k = 1;
    while((k<<1) <= N) k<<=1;
    
    for( ; k>0; k>>=1){
      if( x+k <= N && tree[x+k] < val ){
        val -= tree[x+k];
        x += k;
      }
    }
    return x+1;
  }

  void print(){
    for(int i=0; i<=N; i++){
      cerr << tree[i] << " ";
    }
    cerr << endl;
  }
};


template<class T>
vector<T> compress(vector<T> a, vector<T>& b){
  b = a;
  sort(b.begin(), b.end());
  b.erase( unique(b.begin(), b.end()), b.end());
  for(int i=0; i<a.size(); i++){
    a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
  }
  return a;
}


class TrivialBitVector{
 public:
  vector<int> v;
  vector<int> rank_;
  vector<int> select_0;
  vector<int> select_1;

  TrivialBitVector(vector<int>& v_) : v(v_){
    rank_.resize(v.size()+1, 0);
    for(int i=1; i<=v.size(); i++){
      rank_[i] = rank_[i-1] + v[i-1];
    }

    for(int i=0; i<v.size(); i++){
      (v[i] ? select_1 : select_0).push_back( i );
    }
  }

  int at(int pos){
    assert(0 <= pos && pos < v.size());
    return v[pos];
  }

  //count of q in [0, ub)
  int rank(int q, int ub){
    assert(ub <= v.size());
    int ret = rank_[ub];
    if(q == 0) ret = ub - ret;
    return ret;
  }

  //the position of the (t+1)-th occurrence of q
  int select(int q, int t){
    auto& s = q ? select_1 : select_0;
    if(t >= s.size()) return -1;
    return s[t];
  }
};

// T = unsigned int / unsigned long long
// B = bitvector container type
template<class T, class B>
class WaveletMatrix{
  vector<B> m;
  vector<int> L_size;
  T lg; //left most bit
  T mx;
  const int len;

 public:
  WaveletMatrix(vector<T>& v) : len(v.size()){
    mx = *max_element(v.begin(), v.end());
    lg = 0;
    while((T(1)<<lg+1) <= mx) lg++;

    m.reserve(lg+1);
    L_size.resize(lg+1);

    deque<int> l,r;

    l.resize(len);
    iota(l.begin(), l.end(), 0);

    for(int k=0; k<=lg; k++){
      deque<int> l_, r_;
      vector<int> bits(len);

      L_size[k] = l.size();

      for(int i=0; i<l.size(); i++){
        bits[i] = (v[ l[i] ] >> (lg-k))&1;
        if( (v[ l[i] ] >> (lg-k))&1 ){
          r_.push_back( l[i] );
        }else{
          l_.push_back( l[i] );
        }
      }

      for(int i=0; i<r.size(); i++){
        bits[l.size() + i] = (v[ r[i] ] >> (lg-k))&1;
        if( (v[ r[i] ] >> (lg-k))&1 ){
          r_.push_back( r[i] );
        }else{
          l_.push_back( r[i] );
        }
      }

      swap(l, l_);
      swap(r, r_);
      m.emplace_back(bits);

      /*
      for(int i=0; i<len; i++){
        cerr << bits[i];
      }cerr << endl;
      */
    }
  }

  int count(T q, int lb, int ub){
    return rank(q, ub, lb, 0);
  }

  int count_less_than(T q, int lb, int ub){
    if(ub<=lb) return 0;
    if(q >= mx) return ub-lb;
    return rank_less_than_(q, lb, ub, 0);
  }

  //return t-th occurence position of q
  //if q is not in the list then return -1
  int select(T q, int t){
    if(q >= (T(1)<<lg+1)) return -1;
    return select(q,t, 0,len, 0);
  }


  //return (t+1)-th biggest {value, pos} in [lb,ub)
  pair<int,int> quantile(int lb, int ub, int t, int k=0){
    if(t >= ub-lb) return {-1,-1};

    int val = 0;
    int pos = lb;

    int r = m[k].rank(1, ub);
    int l = m[k].rank(1, lb);

    if(k==lg){
      if(r-l > t){
        pos = m[k].select(1, r-1 - t);
        return {1, pos};
      }else{
        pos = m[k].select(0, ub-1-t-l );
        return {0, pos};
      }
    }
    if( r-l > t ){
      auto tmp = quantile(L_size[k+1] + l, L_size[k+1] + r, t, k+1);
      val = (T(1)<<(lg-k)) | tmp.first;
      pos = m[k].select(1, tmp.second - L_size[k+1]);
    }else{
      auto tmp = quantile(lb-l, ub-r, t-(r-l), k+1);
      val = tmp.first;
      pos = m[k].select(0, tmp.second);
    }
    return {val, pos};
  }

  int quantile_pos(int lb, int ub, int t, int k=0){
    if(t >= ub-lb) return -1;

    int val = 0;
    int pos = lb;

    int r = m[k].rank(1, ub);
    int l = m[k].rank(1, lb);

    if(k==lg){
      if(r-l > t){
        return m[k].select(1, r-1 - t);
      }else{
        return m[k].select(0, ub-1-t-l );
      }
    }
    if( r-l > t ){
      auto tmp = quantile_pos(L_size[k+1] + l, L_size[k+1] + r, t, k+1);
      pos = m[k].select(1, tmp - L_size[k+1]);
    }else{
      auto tmp = quantile_pos(lb-l, ub-r, t-(r-l), k+1);
      pos = m[k].select(0, tmp);
    }
    return pos;
  }

  int quantile_val(int lb, int ub, int t, int k=0){
    if(t >= ub-lb) return -1;
    int val = 0;

    int r = m[k].rank(1, ub);
    int l = m[k].rank(1, lb);

    if(k==lg){
      if(r-l > t){
        return 1;
      }else{
        return 0;
      }
    }
    if( r-l > t ){
      auto tmp = quantile_val(L_size[k+1] + l, L_size[k+1] + r, t, k+1);
      val = (T(1)<<(lg-k)) | tmp;
    }else{
      auto tmp = quantile_val(lb-l, ub-r, t-(r-l), k+1);
      val = tmp;
    }
    return val;
  }

 private:

  //return count of the occurence of q in [0, ub)
  int rank(T q, int ub, int lb=0, int k=0){
    if(q > mx) return 0;
    //ub = min(len, ub);
    int bit = (q>>lg-k) & 1;
    int r = m[k].rank(bit, ub);
    int l = m[k].rank(bit, lb);
    if(k==lg) return r - l;
    if(bit == 0){
      return rank(q, r, l, k+1);
    }else{
      return rank(q, L_size[k+1] + r, L_size[k+1] + l, k+1);
    }
  }

  int rank_less_than_(T q, int lb, int ub, int k=0){
    if(q >= mx) return ub-lb;
    int res = 0;
    int bit = (q>>lg-k) & 1;
    int r = m[k].rank(bit, ub);
    int l = m[k].rank(bit, lb);
    if(bit == 1){
      res += ub-lb - (r-l);
    }
    if(k==lg) return res + r - l;
    if(bit == 0){
      return res + rank_less_than_(q, l, r, k+1);
    }else{
      return res + rank_less_than_(q, L_size[k+1] + l, L_size[k+1] + r, k+1);
    }
  }

  int select(T q, int t, int lb, int ub, int k){
    int bit = (q>>lg-k) & 1;

    int r = m[k].rank(bit, ub);
    int l = m[k].rank(bit, lb);

    if(k==lg){
      return (r-l > t) ? m[k].select(bit, l+t) : -1;
    }else{
      if(bit == 0){
        t = select(q, t, l,r, k+1);
      }else{
        t = select(q, t, L_size[k+1] + l, L_size[k+1] + r, k+1) - L_size[k+1];
      }
      if(t <= -1) return -1;
      
      return m[k].select(bit, t);
    }
  }

};


int main(){
  int n;
  cin >> n;
  vector<long long> a(n);
  cin >> a;

  vector<long long> dic;
  auto aa = compress(a, dic);

  auto check = [&](long long m) -> bool{
    vector<int> x(n+1, n+1);
    for(int i=0; i<n; i++){
      x[i+1] = a[i]<m ? -1 : 1;
    }
    for(int i=1; i<=n; i++){
      x[i] += x[i-1];
    }

    // WaveletMatrix<int, TrivialBitVector> w(x);

    long long big = 0;
    // for(int l=0; l<n; l++){
    //   int tmp = x[l];
    //   long long cnt = w.count_less_than(tmp, l+1, n+1);
    //   big += cnt;
    // }

    BinaryIndexedTree_1_indexed<int> cnt(n*3);
    for(int i=1; i<=n; i++){
      cnt.add(x[i], 1);
    }
    long long sml = 0;
    for(int i=1; i<=n; i++){
      long long base = x[i-1];
      big += cnt.get_sums_range(base, n*3);
      sml += cnt.get_sum(base-1);
      cnt.add( x[i], -1 );
    }
    assert( big + sml == n*(n-1ll)/2 + n);

    return sml <= big;
  };

  long long lb = 0;
  long long ub = dic.size();
  while(ub-lb>1){
    long long mid = (lb+ub)/2;
    bool ok = check(dic[mid]);
    (ok? lb : ub) = mid;
  }

  println(dic[lb]);

  return 0;
}