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-----
3
10 30 20

-----Sample Output-----
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.

Difficulty: interview

Starter code:

Solutions:
def main():
    N, *A = list(map(int, open(0).read().split()))

    B = sorted(A)
    l, r = 0, N
    m, c = N // 2, N * (N + 1) // 2

    def check(x):
        b, r, y = N, 0, 0
        D = [0] * (2 * N + 1)
        for a in A:
            D[b] += 1
            if a < x:
                r += D[b]
                b += 1
            else:
                b -= 1
                r -= D[b]
            y += r
        return y

    while True:
        if check(B[m]) <= c // 2:
            if m == N - 1 or check(B[m + 1]) > c // 2:
                break
            l, m = m, (m + r) // 2
        else:
            m, r = (m + l) // 2, m + 1

    print((B[m]))


def __starting_point():
    main()

__starting_point()

n = int(input())
a = list(map(int, input().split()))
x = list(sorted(set(a)))
n_sub = n * (n + 1) // 2
Li = 0
Ri = len(x)
while Ri > Li + 1:
    i = (Li + Ri) // 2
    xi = x[i]
    UorD = [1 if ak >= xi else -1 for ak in a]
    cnt_sum = [0] * (2 * n + 1)
    cumsum = 0
    cnt_sum[cumsum + n] = 1
    judge = 0
    s = 0
    for uk in UorD:
        cumsum += uk
        if uk == 1:
            s += cnt_sum[cumsum + n] + 1
        else:
            s -= cnt_sum[cumsum + n + 1] - 1
        cnt_sum[cumsum + n] += 1
        judge += s
        if judge >= n_sub // 2:
            Li = i
            break
    else:
        Ri = i
print((x[Li]))


N = int(input())
A = list(map(int, input().split()))
NN = ((N + 1) * N // 2 + 1) // 2

def ok(x):
    B = [0] * (2 * N + 1)
    res, cum, cur = 0, 0, 0
    B[0] += 1
    for a in A:
        if a >= x:
            cum += 1
            cur += B[cum]+1
        else:
            cur -= B[cum]-1
            cum -= 1
        B[cum] += 1
        res += cur
    return res >= NN

B = sorted(set(A))
l = 0
r = len(B)
while r - l > 1:
    m = (l + r) // 2
    if ok(B[m]):
        l = m
    else:
        r = m
print(B[l])


def median_of_medians(N: int, A: list)->int:
    def search(c):
        bar = N
        r = 0
        res_nega = 0
        dp_arr = [0]*(2*N+1)
        for i in range(N):
            dp_arr[bar] += 1
            if A[i] < c:
                r += dp_arr[bar]
                bar += 1
            else:
                r -= (dp_arr[bar-1])
                bar -= 1
            res_nega += r
        return res_nega

    # binary search
    a_sorted = sorted(A)
    left = 0
    right = N
    mid = N // 2
    C = N*(N+1) // 2
    while True:
        if search(a_sorted[mid]) <= C // 2:
            if mid == N-1:
                break
            elif search(a_sorted[mid+1]) > C // 2:
                break
            else:
                left = mid
                mid = (mid + right) // 2
        else:
            right = mid + 1
            mid = (mid + left) // 2

    return a_sorted[mid]


def __starting_point():
    N = int(input())
    A = [int(s) for s in input().split()]
    ans = median_of_medians(N, A)
    print(ans)

__starting_point()

n=int(input())
a=list(map(int,input().split()))
a2=sorted(set(a))
L=len(a2)
if n==1:print(a[0]);return
elif n==2:print(a[1]);return
ng=L
ok=0
while ng-ok>1:
    check=a2[(ok+ng)//2]
    cnt=0 #check以上の要素の数
    idx=n
    cl=[0]*(2*n+1)
    cl[n]=1
    Ru=0
    for i in range(n):
        if a[i]<check:
            Ru-=cl[idx]-1
            idx-=1
        else:
            idx+=1
            Ru+=cl[idx]+1
        cnt += Ru
        cl[idx]+=1
    if cnt >= ((n+1)*n//2)//2:
        ok = (ok+ng)//2
    else:
        ng = (ok+ng)//2
print(a2[ok])

def f(n, a):
    x = list(sorted(set(a)))
    n_sub_half = n * (n + 1) // 2 // 2
    n_plus_minus = n * 2 + 1
    Li = 0
    Ri = len(x)
    while Ri > Li + 1:
        i = (Li + Ri) // 2
        xi = x[i]
        cnt_sum = [0] * n_plus_minus
        cumsum = 0
        cnt_sum[cumsum] = 1
        judge = 0
        s = 0
        for ak in a:
            if ak >= xi:
                cumsum += 1
                s += cnt_sum[cumsum] + 1
            else:
                cumsum -= 1
                s -= cnt_sum[cumsum + 1] - 1
            cnt_sum[cumsum] += 1
            judge += s
            if judge >= n_sub_half:
                Li = i
                break
        else:
            Ri = i
    print(x[Li])

n = int(input())
a = list(map(int, input().split()))
f(n, a)

def f(n, a):
    x = list(sorted(set(a)))
    n_sub_half = n * (n + 1) // 2 // 2
    n_plus_minus = n * 2 + 1
    Li = 0
    Ri = len(x)
    while Ri > Li + 1:
        i = (Li + Ri) // 2
        xi = x[i]
        cnt_sum = [0] * n_plus_minus
        cumsum = 0
        cnt_sum[cumsum] = 1
        judge = 0
        s = 0
        for ak in a:
            if ak >= xi:
                cumsum += 1
                s += cnt_sum[cumsum] + 1
            else:
                cumsum -= 1
                s -= cnt_sum[cumsum + 1] - 1
            cnt_sum[cumsum] += 1
            judge += s
            if judge >= n_sub_half:
                Li = i
                break
        else:
            Ri = i
    print((x[Li]))


n = int(input())
a = list(map(int, input().split()))
f(n, a)


n = int(input())
A = list(map(int, input().split()))

def search(x):
    b = n
    r = 0
    y = 0
    D = [0]*(2*n+1)
    for i in range(n):
        D[b] += 1
        if A[i] < x:
            r += D[b]
            b += 1
        else:
            b -= 1
            r -= D[b]   
        y += r
    return y

S = sorted(A)
l = 0
r = n
m = n // 2
c = n * (n + 1) // 2

while True:
    if search(S[m]) <= c // 2:
        if m == n - 1:
            break
        elif search(S[m + 1]) > c // 2:
            break
        else:
            l = m
            m = (m + r) // 2
    else:
        r = m + 1
        m = (m + l) // 2
        
print((S[m]))


n=int(input())
a=list(map(int,input().split()))
a2=sorted(set(a))
L=len(a2)
if n==1:print(a[0]);return
elif n==2:print(a[1]);return
ng=L
ok=0
while ng-ok>1:
    check=a2[(ok+ng)//2]
    cnt=0 #check以上の要素の数
    idx=n
    cl=[0]*(2*n+1)
    cl[n]=1
    Ru=0
    for i in range(n):
        if a[i]<check:
            Ru-=cl[idx]-1
            idx-=1
        else:
            idx+=1
            Ru+=cl[idx]+1
        cnt += Ru
        cl[idx]+=1
    if cnt >= ((n+1)*n//2)//2:
        ok = (ok+ng)//2
    else:
        ng = (ok+ng)//2

print(a2[ok])

N = int(input())
A = list(map(int, input().split()))
 
sortA = sorted(set(A)) + [float('inf')]
 
def isOk(n):
    x = sortA[n]
    count = [0 for _ in range(2 * N + 1)]
    count[N + 1] = 1
 
    i = N + 1
    s = 1
    result = 0
 
    for a in A:
        if a >= x:
            i += 1
            s += count[i]
        else:
            s -= count[i]
            i -= 1
        result += s
        count[i] += 1
        s += 1
 
    if result >= N * (N + 1) // 4:
        return False
    else:
        return True
 
 
left = 0
right = len(sortA) - 1
 
while right - left > 1:
    mid = (left + right ) // 2
 
    if isOk(mid):
        right = mid
    else:
        left = mid
 
print(sortA[left])

def main():
    n,*a=map(int,open(0).read().split())
    m=n*-~n//2+1>>1
    ng=max(a)+1
    ok=0
    while ng-ok>1:
        mid=ok+ng>>1
        b=[1]+[0]*n*2
        c=d=s=0
        for t in a:
            if t>=mid:
                c+=1
                d+=b[c]+1
            else:
                d-=b[c]-1
                c-=1
            b[c]+=1
            s+=d
        if s>=m:ok=mid
        else:ng=mid
    print(ok)
main()

import numpy as np
from collections import defaultdict

N = int(input())
A = np.array(input().split(), dtype=np.int32)
total_medians = N*(N+1)//2
# n件のデータ
# (上側中央値 >= x) iff (a > x となる a が(n-1)//2以下)

def test(x):
  # 「答はx以下である」
  # 「xより真に大きな区間中央値が(total_medians-1)//2個以下」
  # xより真に大きな値を1、他を-1とする。
  # 1の個数が-1の個数以上になっている区間
  current = 0 # 累積和
  memo = defaultdict(int) # 過去の累積和の分布, incl empty
  memo[0] = 1
  cnt_below = 1 # sum memo[y] for y <= x
  result = 0
  for a in A:
    if a > x:
      current += 1
      cnt_below += memo[current]
    else:
      cnt_below -= memo[current]
      current -= 1
    result += cnt_below
    memo[current] += 1
    cnt_below += 1
  return result <= (total_medians-1)//2

AA = sorted(A)
left = -1 # 答はAA[left]より大きい
right = len(AA)-1 # 答はAA[right]以下である
while right - left > 1:
  mid = (left+right)//2
  if test(AA[mid]):
    right = mid
  else:
    left = mid
    
answer = AA[right]
print(answer)


def bisect_right_callable(fn, x, lo, hi):
    """
    lo から hi-1 のうち、fn の結果が x 以下となる、最も右の値 + 1
    bisect.bisect_right と同じ
    https://docs.python.org/ja/3/library/bisect.html
    :param callable fn:
    :param x:
    :param int lo: 最小値
    :param int hi: 最大値 + 1
    :return: lo <= ret <= hi
    """
    while lo < hi:
        mid = (lo + hi) // 2
        if x < fn(mid):
            hi = mid
        else:
            lo = mid + 1
    return lo


N = int(input())
series = list(map(int, input().split()))
series_sorted = sorted(series)

# L と r の選び方の組み合わせ数。1 から N までの和に等しい
lr_size = (N + 1) * N / 2


def count_lr(x):
    """
    x 以上の数を半分以上含む == 中央値が x 以上である、L と r の選び方の数
    :param x:
    :return:
    """
    ret = 0
    # series[i] が x 未満なら 1、x 以上なら -1 を i番目に持つ配列の、i=0 から i までの累積和。
    cumsum = 0
    # counts[i]: cumsum が i に何回なったか
    counts = {i: 0 for i in range(-N, N + 1)}
    counts[cumsum] = 1
    diff = 0
    for i in range(N):
        if series[i] >= x:
            cumsum += 1
            counts[cumsum] += 1
            diff += counts[cumsum]
        else:
            cumsum -= 1
            counts[cumsum] += 1
            diff -= counts[cumsum + 1] - 1
        ret += diff
    return ret


# count_lr(x) の結果が半分以上であれば、中央値は x 以上。
# count_lr(x) が半分以上のうち一番大きい x を探す。
def solve(i):
    if count_lr(series_sorted[i]) >= (lr_size + 1) // 2:
        return 0
    else:
        return float('inf')


ans_i = bisect_right_callable(solve, 0, lo=0, hi=N)
print((series_sorted[max(0, min(N - 1, ans_i - 1))]))


n = int(input())
a = list(map(int, input().split()))
x = list(sorted(set(a)))
n_sub = n * (n + 1) // 2
Li = 0
Ri = len(x)
while Ri > Li + 1:
    i = (Li + Ri) // 2
    xi = x[i]
    UorD = [1 if ak >= xi else -1 for ak in a]
    cnt_sum = [0] * (2 * n + 1)
    cumsum = 0
    cnt_sum[cumsum + n] = 1
    judge = 0
    s = 0
    for uk in UorD:
        cumsum += uk
        if uk == 1:
            s += cnt_sum[cumsum + n] + 1
        else:
            s -= cnt_sum[cumsum + n + 1] - 1
        cnt_sum[cumsum + n] += 1
        judge += s
        if judge >= n_sub // 2:
            Li = i
            break
    else:
        Ri = i
print((x[Li]))


def main():
    N, *A = list(map(int, open(0).read().split()))

    B = sorted(A)
    l, r = 0, N
    m, c = N // 2, N * (N + 1) // 2

    def check(x):
        b, r, y = N, 0, 0
        D = [0] * (2 * N + 1)
        for a in A:
            D[b] += 1
            if a < x:
                r += D[b]
                b += 1
            else:
                b -= 1
                r -= D[b]
            y += r
        return y

    while True:
        if check(B[m]) <= c // 2:
            if m == N - 1 or check(B[m + 1]) > c // 2:
                break
            else:
                l, m = m, (m + r) // 2
        else:
            m, r = (m + l) // 2, m + 1

    print((B[m]))


def __starting_point():
    main()

__starting_point()

N = int(input())
a_list = list(map(int, input().split()))
def search(c):
    bar = N
    r = 0
    res_nega = 0
    dp_arr = [0]*(2*N+1)
    for i in range(N):
        dp_arr[bar] += 1
        if a_list[i] < c:
            r += dp_arr[bar]
            bar += 1
        else:
            r -= (dp_arr[bar-1])
            bar -= 1
        res_nega += r
    return res_nega
# binary search
a_sorted = sorted(a_list)
left = 0
right = N
mid = N // 2
C = N*(N+1) // 2
while True:
    if search(a_sorted[mid]) <= C // 2:
        if mid == N-1:
            break
        elif search(a_sorted[mid+1]) > C // 2:
            break
        else:
            left = mid
            mid = (mid + right) // 2
    else:
        right = mid + 1
        mid = (mid + left) // 2
print((a_sorted[mid]))


def main():
    N, *A = map(int, open(0).read().split())
 
    B = sorted(A)
    l, r = 0, N
    m, c = N // 2, N * (N + 1) // 2
 
    def check(x):
        b, r, y = N, 0, 0
        D = [0] * (2 * N + 1)
        for a in A:
            D[b] += 1
            if a < x:
                r += D[b]
                b += 1
            else:
                b -= 1
                r -= D[b]
            y += r
        return y
 
    while True:
        if check(B[m]) <= c // 2:
            if m == N - 1 or check(B[m + 1]) > c // 2:
                break
            else:
                l, m = m, (m + r) // 2
        else:
            m, r = (m + l) // 2, m + 1
 
    print(B[m])
 
 
def __starting_point():
    main()
__starting_point()

n = int(input())
a = list(map(int, input().split()))

def check(x):
    b = n
    r = 0
    y = 0
    D = [0]*(2*n+1)
    for i in range(n):
        D[b] += 1
        if a[i] < x:
            r += D[b]
            b += 1
        else:
            b -= 1
            r -= D[b]
        y += r
    return y

alpha = sorted(a)
l, r = 0, n
m, c = n//2, n*(n+1)//2
while True:
    if check(alpha[m]) <= c//2:
        if m == n-1:
            break
        elif check(alpha[m+1]) > c//2:
            break
        else:
            l, m = m, (m+r)//2
    else:
        m, r = (m+l)//2, m+1
        
print(alpha[m])

n = int(input())
a = list(map(int, input().split()))
x = list(sorted(set(a)))
n_sub = n * (n + 1) // 2
Li = 0
Ri = len(x)
while Ri > Li + 1:
    i = (Li + Ri) // 2
    xi = x[i]
    UorD = [1 if ak >= xi else -1 for ak in a]
    cnt_sum = [0] * (2 * n + 1)
    cumsum = 0
    cnt_sum[cumsum + n] = 1
    judge = 0
    s = 0
    for uk in UorD:
        cumsum += uk
        if uk == 1:
            s += cnt_sum[cumsum + n] + 1
        else:
            s -= cnt_sum[cumsum + n + 1] - 1
        cnt_sum[cumsum + n] += 1
        judge += s
        if judge >= n_sub // 2:
            Li = i
            break
    else:
        Ri = i
print((x[Li]))