You are given a sequence with N integers: A = \{ A_1, A_2, \cdots, A_N \}.
For each of these N integers, we will choose a color and paint the integer with that color. Here the following condition must be satisfied:
 - If A_i and A_j (i < j) are painted with the same color, A_i < A_j.
Find the minimum number of colors required to satisfy the condition.

-----Constraints-----
 - 1 \leq N \leq 10^5
 - 0 \leq A_i \leq 10^9

-----Input-----
Input is given from Standard Input in the following format:
N
A_1
:
A_N

-----Output-----
Print the minimum number of colors required to satisfy the condition.

-----Sample Input-----
5
2
1
4
5
3

-----Sample Output-----
2

We can satisfy the condition with two colors by, for example, painting 2 and 3 red and painting 1, 4, and 5 blue.

Difficulty: MEDIUM

Solutions:
import bisect
(n, *a) = list(map(int, open(0).read().split()))
a = a[::-1]
INF = 1 << 30
dp = [INF] * (n + 1)
for e in a:
	dp[bisect.bisect_right(dp, e)] = e
print(bisect.bisect_left(dp, INF))


import bisect
N = int(input())
A = [int(input()) for i in range(N)]
S = []
for i in range(N):
	posi = bisect.bisect_left(S, A[i])
	if posi == 0:
		S.insert(0, A[i])
	else:
		S[posi - 1] = A[i]
print(len(S))


import heapq
import bisect
N = int(input())
A = []
for i in range(N):
	a = int(input())
	A.append(a)
h = []
c = 0
for i in range(N - 1, -1, -1):
	p = bisect.bisect_right(h, A[i])
	if p == len(h):
		h.append(A[i])
		c += 1
	else:
		h[p] = A[i]
print(c)


import bisect
n = int(input())
colors = [-int(input())]
for _ in range(n - 1):
	a = int(input())
	i = bisect.bisect_right(colors, -a)
	if i == len(colors):
		colors.append(-a)
	else:
		colors[i] = -a
print(len(colors))


from collections import deque
from bisect import bisect_left
n = int(input())
a = [int(input()) for i in range(n)]
d = deque()
for i in range(n):
	b = bisect_left(d, a[i])
	if b == 0:
		d.appendleft(a[i])
	else:
		d[b - 1] = a[i]
print(len(d))


import sys
input = sys.stdin.readline

def bisect_right_reverse(L, target):
	ok = len(L)
	ng = -1
	while ok - ng > 1:
		mid = (ok + ng) // 2
		if L[mid] < target:
			ok = mid
		else:
			ng = mid
	return ok
N = int(input())
A = [int(input()) for _ in range(N)]
L = []
for i in range(N):
	k = bisect_right_reverse(L, A[i])
	if k == len(L):
		L.append(A[i])
	else:
		L[k] = A[i]
print(len(L))


import bisect
n = int(input())
a = []
for i in range(n):
	x = int(input())
	a.append(x)
a = a[::-1]
stack = [a[0]]
for i in range(1, n):
	index = bisect.bisect_right(stack, a[i])
	if index == len(stack):
		stack.append(a[i])
	else:
		stack[index] = a[i]
print(len(stack))


N = int(input())
A = list((int(input()) for _ in range(N)))
S = [A[0]]
for i in range(1, N):
	if A[i] <= S[0]:
		S.insert(0, A[i])
		continue
	ok = 0
	ng = len(S)
	tmp = ok + ng
	while ok + 1 < ng:
		tmp = (ok + ng) // 2
		if A[i] > S[tmp]:
			ok = tmp
		else:
			ng = tmp
	S[ok] = A[i]
print(len(S))


from bisect import bisect_right
(N, *A) = map(int, open(0).read().split())
A = [-a for a in A]
q = []
for a in A:
	idx = bisect_right(q, a)
	if idx == len(q):
		q.append(a)
	else:
		q[idx] = a
print(len(q))


import bisect

def main():
	INF = 10 ** 10
	N = int(input())
	A = [int(input()) for _ in range(N)]
	A.reverse()
	B = [INF for _ in range(N)]
	for a in A:
		index = bisect.bisect_right(B, a)
		B[index] = a
	ans = 0
	for b in B:
		if b == INF:
			break
		ans += 1
	print(ans)

def __starting_point():
	main()
__starting_point()


import bisect
N = int(input())
L = []
L.append(-int(input()))
c = 1
for i in range(N - 1):
	A = -int(input())
	x = bisect.bisect_right(L, A)
	if x == c:
		L.append(A)
		c += 1
	else:
		L[x] = A
print(c)


import bisect
N = int(input())
A = [-int(input()) for _ in range(N)]
tmp = [A[0]]
for i in A[1:N]:
	index = bisect.bisect(tmp, i)
	if index == len(tmp):
		tmp.append(i)
	else:
		tmp[index] = i
print(len(tmp))


from bisect import *
N = int(input())
A = [-int(input()) for i in range(N)]
dp = [float('inf')] * N
for i in range(N):
	ind = bisect_right(dp, A[i])
	dp[ind] = A[i]
ans = bisect_left(dp, float('inf'))
print(ans)


from bisect import bisect_left, bisect_right
n = int(input())
INF = 1010101010
dp = [INF] * n
a = [int(input()) for _ in range(n)]
a.reverse()
for i in a:
	dp[bisect_right(dp, i)] = i
print(bisect_left(dp, INF))


from collections import deque
import bisect
N = int(input())
table = deque()
for n in range(N):
	a = int(input())
	if n == 0:
		table.append(a)
	elif a <= table[0]:
		table.appendleft(a)
	else:
		table[bisect.bisect_left(table, a) - 1] = a
print(len(table))


from bisect import bisect_left, bisect_right
N = int(input())
seq = [0] * N
for i in range(N):
	seq[i] = -1 * int(input())

def getLIS(_N, a):
	INF = 1e+18
	MaxP = _N + 10
	dp = [INF for _ in range(MaxP)]
	for i in range(_N):
		dp[bisect_right(dp, a[i])] = a[i]
	return dp[:bisect_left(dp, INF)]
LIS2 = getLIS(N, seq)
print(len(LIS2))


from bisect import bisect_right
n = int(input())
a = int(input())
x = [a * -1]
for _ in range(n - 1):
	a = int(input()) * -1
	if a >= x[-1]:
		x.append(a)
	else:
		index = bisect_right(x, a)
		x[index] = a
print(len(x))


from collections import deque
import bisect
N = int(input())
A = [int(input()) for _ in range(N)]
Q = deque([A[0]])
for a in A[1:]:
	if a <= Q[0]:
		Q.appendleft(a)
	else:
		idx = bisect.bisect_left(Q, a)
		Q[idx - 1] = a
print(len(Q))


import bisect
N = int(input())
ls = [int(input()) for _ in range(N)]
color = [ls[-1]]
ans = 1
for i in range(N - 1):
	a = ls[-2 - i]
	k = bisect.bisect_right(color, a)
	if k == ans:
		color.append(a)
		ans += 1
	else:
		color[k] = a
print(ans)


from collections import deque
from bisect import bisect_left
N = int(input())
A = [int(input()) for _ in range(N)]
q = deque([A[0]])
for x in A[1:]:
	i = bisect_left(q, x)
	if i == 0:
		q.appendleft(x)
	else:
		q[i - 1] = x
print(len(q))


import sys
from bisect import bisect_right
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60

def main():
	(N, *A) = list(map(int, read().split()))
	vec = [INF] * N
	for a in reversed(A):
		vec[bisect_right(vec, a)] = a
	print(N - vec.count(INF))
	return

def __starting_point():
	main()
__starting_point()


import bisect
n = int(input())
A = []
for i in range(n):
	A.append(int(input()))
Ans = [A[-1]]
for i in reversed(range(n - 1)):
	a = A[i]
	if a >= Ans[-1]:
		Ans.append(a)
	else:
		Ans[bisect.bisect_right(Ans, a)] = a
print(len(Ans))


N = int(input())
L = []
from bisect import bisect_right
for _ in range(N):
	u = -int(input())
	index = bisect_right(L, u)
	if index == len(L):
		L.append(u)
	else:
		L[index] = u
print(len(L))


from bisect import bisect_right, insort_right
N = int(input())
A = [int(input()) for _ in range(N)][::-1]
res = [A[0]]
for a in A[1:]:
	idx = bisect_right(res, a)
	if idx == len(res):
		res.append(a)
	elif res[idx] == a:
		insort_right(res, a)
	else:
		res[idx] = a
print(len(res))


from bisect import bisect_right
n = int(input())
A = [-int(input()) for _ in range(n)]
B = []
for a in A:
	b = bisect_right(B, a)
	if len(B) == b:
		B.append(a)
	else:
		B[b] = a
print(len(B))


from bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)]
INF = 10 ** 18
dp = [INF] * N
for a in A:
	dp[bisect_right(dp, -a)] = -a
ans = N - dp.count(INF)
print(ans)


from collections import *
from bisect import *
(N, *A) = map(int, open(0))
q = deque([A[0]])
for x in A[1:]:
	i = bisect_left(q, x)
	if i == 0:
		q.appendleft(x)
	else:
		q[i - 1] = x
print(len(q))


from collections import deque
from bisect import bisect_left
N = int(input())
A = [int(input()) for _ in range(N)]
que = deque()
for i in range(N):
	k = bisect_left(que, A[i])
	if k == 0:
		que.appendleft(A[i])
	else:
		que[k - 1] = A[i]
print(len(que))


import bisect
n = int(input())
arr = [int(input()) for _ in range(n)]
num = 1
ans = [-arr[0]]
for i in range(1, n):
	if -arr[i] >= ans[-1]:
		ans.append(-arr[i])
	else:
		pos = bisect.bisect_right(ans, -arr[i])
		ans[pos] = -arr[i]
print(len(ans))


from bisect import bisect_right
n = int(input())
a = [-int(input()) for _ in range(n)]
li = list()
for e in a:
	i = bisect_right(li, e)
	if i == len(li):
		li.append(e)
	else:
		li[i] = e
ans = len(li)
print(ans)


import bisect
INF = 10000000000
n = int(input())
a = [0] * n
for i in range(n):
	a[i] = int(input())
	a[i] = -a[i]
dp = [INF] * n
for i in range(n):
	dp[bisect.bisect_right(dp, a[i])] = a[i]
print(bisect.bisect_left(dp, INF))


from bisect import bisect_right
N = int(input())
A = []
for i in range(N):
	A.append(-int(input()))
INF = float('inf')
D = [INF] * N
for i in range(len(A)):
	D[bisect_right(D, A[i])] = A[i]
print(N - D.count(INF))


import bisect
from collections import deque
N = int(input())
A = [int(input()) for i in [0] * N]
ls = deque([A[0]])
for a in A[1:]:
	ind = bisect.bisect_left(ls, a)
	if ind == 0:
		ls.appendleft(a)
	else:
		ls[ind - 1] = a
print(len(ls))


import bisect
N = int(input())
A = [-int(input()) for i in range(N)]
dp = []
for a in A:
	i = bisect.bisect_right(dp, a)
	if i >= len(dp):
		dp.append(a)
	else:
		dp[i] = a
print(len(dp))


from bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)]
ans = 1
min_vs = [A[-1]]
for i in range(N - 2, -1, -1):
	a = A[i]
	idx = bisect_right(min_vs, a)
	if idx == len(min_vs):
		ans += 1
		min_vs.append(a)
	else:
		min_vs[idx] = a
print(ans)


N = int(input())
A = [int(input()) for i in range(N)]
from bisect import bisect
arr = []
for a in A:
	i = bisect(arr, -a)
	if i == len(arr):
		arr.append(-a)
	else:
		arr[i] = -a
print(len(arr))


import bisect
N = int(input())
A = [10 ** 10 - int(input()) for i in range(N)]
INF = 10 ** 12
dp = [INF for i in range(N + 1)]
for a in A:
	i = bisect.bisect_right(dp, a)
	dp[i] = a
res = bisect.bisect_left(dp, INF)
print(res)


from bisect import bisect_left
from collections import deque
n = int(input())
A = [int(input()) for _ in range(n)]
D = deque([])
for a in A:
	i = bisect_left(D, a)
	if i == 0:
		D.appendleft(a)
	else:
		D[i - 1] = a
print(len(D))


import bisect
N = int(input())
A = [int(input()) for i in range(N)]

def lis(S):
	from bisect import bisect_right
	L = [S[0]]
	for s in S[1:]:
		if s >= L[-1]:
			L.append(s)
		else:
			L[bisect_right(L, s)] = s
	return len(L)
print(lis(A[::-1]))


import sys
readline = sys.stdin.readline
N = int(readline())
ans = []
import bisect
for i in range(N):
	a = -int(readline())
	ind = bisect.bisect_right(ans, a)
	if ind == len(ans):
		ans.append(a)
	else:
		ans[ind] = a
print(len(ans))


import bisect
N = int(input())
seq = [-int(input()) for i in range(N)]
LIS = [seq[0]]
for i in range(1, len(seq)):
	if seq[i] >= LIS[-1]:
		LIS.append(seq[i])
	else:
		LIS[bisect.bisect_right(LIS, seq[i])] = seq[i]
print(len(LIS))


import sys
from bisect import bisect_right
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007

def main():
	(N, *A) = list(map(int, read().split()))
	vec = [A[-1]]
	for a in reversed(A[:-1]):
		if a >= vec[-1]:
			vec.append(a)
		else:
			vec[bisect_right(vec, a)] = a
	print(len(vec))
	return

def __starting_point():
	main()
__starting_point()


from collections import deque
import bisect
n = int(input())
L = deque([int(input())])
for i in range(1, n):
	t = int(input())
	k = bisect.bisect_left(L, t)
	if k == 0:
		L.appendleft(t)
	else:
		L[k - 1] = t
print(len(L))


import sys
import bisect
input = sys.stdin.readline
N = int(input())
A = [-int(input()) for _ in range(N)]
l = [A[0]]
for x in A[1:]:
	tmp = bisect.bisect(l, x)
	if tmp == len(l):
		l.append(x)
	else:
		l[tmp] = x
print(len(l))


import bisect
n = int(input())
a = [int(input()) for _ in range(n)]
dp = [float('inf')] * n
for i in range(n):
	c = a[n - i - 1]
	b = bisect.bisect_right(dp, c)
	if dp[b] > c:
		dp[b] = c
print(bisect.bisect_right(dp, 10 ** 9 + 1))


import sys
input = sys.stdin.readline
from collections import deque
N = int(input())
A = [int(input()) for _ in range(N)]
INF = 10 ** 18
arr = deque([])
for a in A:
	(l, r) = (-1, len(arr))
	while r - l > 1:
		mid = (r + l) // 2
		if arr[mid] < a:
			l = mid
		else:
			r = mid
	if l == -1:
		arr.appendleft(a)
	else:
		arr[l] = a
print(len(arr))


from collections import deque
from bisect import bisect_left
n = int(input())
a = [int(input()) for _ in range(n)]
dq = deque()
for e in a:
	i = bisect_left(dq, e)
	if i == 0:
		dq.appendleft(e)
	else:
		dq[i - 1] = e
ans = len(dq)
print(ans)


from bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)]
A = A[::-1]
LIS = []
for ai in A:
	index = bisect_right(LIS, ai)
	if index >= len(LIS):
		LIS.append(ai)
	else:
		LIS[index] = ai
print(len(LIS))


n = int(input())
a = [-1 * int(input()) for _ in range(n)]
dp = [10 ** 18 for _ in range(n)]
import bisect

def lis(a):
	seq = []
	tmp = 0
	for i in a:
		pos = bisect.bisect_right(seq, i)
		if tmp <= pos:
			seq.append(i)
			tmp += 1
		else:
			seq[pos] = i
	return tmp
print(lis(a))


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left, bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil, pi, factorial
from operator import itemgetter

def I():
	return int(input())

def MI():
	return list(map(int, input().split()))

def LI():
	return list(map(int, input().split()))

def LI2():
	return [int(input()) for i in range(n)]

def MXI():
	return [[LI()] for i in range(n)]

def SI():
	return input().rstrip()

def printns(x):
	print('\n'.join(x))

def printni(x):
	print('\n'.join(list(map(str, x))))
inf = 10 ** 17
mod = 10 ** 9 + 7
n = I()
lis = [I() for i in range(n)]
cols = deque([inf])
i = 0
while i < n:
	x = lis[i]
	if cols[0] >= x:
		cols.appendleft(x)
	else:
		cols[bisect_left(cols, x) - 1] = x
	i += 1
print(len(cols) - 1)


import bisect
N = int(input())
A = [-int(input()) for _ in range(N)]
x = [A[0]]
for a in A[1:]:
	i = bisect.bisect(x, a)
	if i == len(x):
		x.append(a)
	else:
		x[i] = a
print(len(x))


from collections import deque
import bisect
N = int(input())
L = deque()
for i in range(N):
	s = int(input())
	if i == 0:
		L.append(s)
	elif s <= L[0]:
		L.appendleft(s)
	else:
		L[bisect.bisect(L, s - 1) - 1] = s
print(len(L))


import bisect
n = int(input())
a = [int(input()) for i in range(n)]
c = [a[-1]]
for i in a[n - 2::-1]:
	if c[-1] <= i:
		c.append(i)
	else:
		c[bisect.bisect_left(c, i + 1)] = i
print(len(c))


from bisect import bisect_right as br
n = int(input())
a = [int(input()) for _ in range(n)][::-1]
INF = float('INF')
lst = [INF] * n
ans = 0
for i in range(n):
	l = br(lst, a[i])
	lst[l] = a[i]
	ans = max(l + 1, ans)
print(ans)


import bisect
import collections
N = int(input())
A = [int(input()) for _ in range(N)]
C = collections.deque()
for a in A:
	p = bisect.bisect_left(C, a)
	if p == 0:
		C.appendleft(a)
	else:
		C[p - 1] = a
print(len(C))


import bisect
from collections import deque
n = int(input())
A = deque([int(input())])
for i in range(n - 1):
	a = int(input())
	b = bisect.bisect_left(A, a, lo=0, hi=len(A))
	if b == 0:
		A.appendleft(a)
	else:
		A[b - 1] = a
print(len(A))


from bisect import bisect
(N, *A) = map(int, open(0).read().split())
INF = 10 ** 9 + 7
dp = [INF] * (N + 1)
for i in range(N):
	dp[bisect(dp, -A[i])] = -A[i]
print(sum((dp[i] < INF for i in range(N))))


import bisect
n = int(input())
a_ls = []
for i in range(n):
	a_ls.append(-int(input()))
L_ls = [a_ls[0]]
for a in a_ls[1:]:
	if L_ls[-1] <= a:
		L_ls.append(a)
	else:
		L_ls[bisect.bisect_right(L_ls, a)] = a
print(len(L_ls))


import bisect
(n, a, l) = (int(input()), [-int(input())], 1)
for i in range(n - 1):
	b = -int(input())
	if a[-1] > b:
		a[bisect.bisect_right(a, b)] = b
	else:
		a.append(b)
		l += 1
print(l)


import sys
import bisect

def input():
	return sys.stdin.readline().rstrip()

def main():
	n = int(input())
	A = [0] * n
	for i in range(1, n + 1):
		A[-i] = int(input())
	inf = 10 ** 10
	dp = [0]
	for AA in A:
		if dp[-1] <= AA:
			dp.append(AA)
		else:
			bis = bisect.bisect_right(dp, AA)
			dp[bis] = AA
	print(len(dp) - 1)

def __starting_point():
	main()
__starting_point()


import sys
from bisect import bisect_left
from bisect import bisect_right
INF = float('inf')

def main():
	N = int(input())
	A = [int(input()) for _ in range(N)]
	dp = [INF] * N
	for i in range(N):
		j = bisect_right(dp, -A[i])
		dp[j] = -A[i]
	print(bisect_left(dp, INF))

def __starting_point():
	main()
__starting_point()


import bisect
from collections import deque
N = int(input())
A = [int(input()) for _ in range(N)]
dp = deque()
dp.append(A[0])
for i in range(1, N):
	ind = bisect.bisect_left(dp, A[i])
	if ind == 0:
		dp.appendleft(A[i])
	elif dp[-1] < A[i]:
		dp[-1] = A[i]
	else:
		dp[ind - 1] = A[i]
print(len(dp))


import bisect
a = [-int(input()) for _ in [0] * int(input())]
dp = []
for x in a:
	i = bisect.bisect(dp, x)
	if i == len(dp):
		dp.append(x)
	else:
		dp[i] = min(dp[i], x)
print(len(dp))


import bisect
N = int(input())
A = [-int(input()) for i in range(N)]
X = []
for i in range(N):
	a = A[i]
	idx = bisect.bisect_left(X, a + 0.1)
	if idx == len(X):
		X.append(a)
	else:
		X[idx] = a
print(len(X))


import sys, bisect
input = sys.stdin.readline
n = int(input())
a = [int(input()) for _ in range(n)]
a.reverse()
dp = [float('inf')] * (n + 1)
for b in a:
	idx = bisect.bisect_right(dp, b)
	dp[idx] = b
ans = bisect.bisect_left(dp, float('inf'))
print(ans)


from bisect import bisect_right
n = int(input())
ans = 1
data = [-int(input())]
for i in range(n - 1):
	x = -int(input())
	j = bisect_right(data, x)
	if j == ans:
		data.append(x)
		ans += 1
	else:
		data[j] = x
print(ans)


n = int(input())
a = [-int(input()) for i in range(n)]
from bisect import bisect_right
l = []
for aa in a:
	idx = bisect_right(l, aa)
	if idx == len(l):
		l.append(aa)
	else:
		l[idx] = aa
print(len(l))


from bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)]
A.reverse()
L = [A[0]]
for a in A[1:]:
	if a >= L[-1]:
		L.append(a)
	else:
		L[bisect_right(L, a)] = a
print(len(L))


from bisect import bisect_left
N = int(input())
(A, c) = (list(range(N)), [])
for i in range(N):
	A[i] = int(input())
for x in reversed(A):
	p = bisect_left(c, x + 1)
	if p == len(c):
		c.append(x)
	else:
		c[p] = x
print(len(c))


from bisect import bisect_left
n = int(input())
a = [int(input()) for _ in range(n)]
c = [0] * n
end = n
for ai in a:
	ci = bisect_left(c, ai, end, n)
	c[ci - 1] = ai
	if ci <= end:
		end -= 1
print(n - end)


from bisect import bisect
(N, *A) = map(int, open(0).read().split())
mins = []
length = 0
for a in A:
	i = bisect(mins, -a)
	if i >= length:
		mins.append(-a)
		length += 1
	else:
		mins[i] = -a
print(length)


n = int(input())
a = []
for i in range(n):
	a.append(-int(input()))
dp = [10 ** 10 for i in range(n + 1)]
import bisect
for i in a:
	idx = bisect.bisect_right(dp, i)
	dp[idx] = i
ans = bisect.bisect_left(dp, 10 ** 10)
print(ans)


from collections import deque
import bisect
N = int(input())
A = [int(input()) for i in range(N)]
q = deque([A[0]])
for a in A[1:]:
	idx = bisect.bisect_left(q, a)
	if idx == 0:
		q.appendleft(a)
	else:
		q[idx - 1] = a
print(len(q))


from bisect import bisect_right, bisect_left
n = int(input())
a = [int(input()) for _ in range(n)]
INF = float('INF')
l = [INF] * n
for i in a[::-1]:
	l[bisect_right(l, i)] = i
print(bisect_left(l, INF))


import bisect
from collections import deque
N = int(input())
a = deque([int(input())])
for _ in range(N - 1):
	num = int(input())
	if num <= a[0]:
		a.appendleft(num)
	else:
		a[bisect.bisect_left(a, num) - 1] = num
print(len(a))


import bisect
n = int(input())
a = [int(input()) for i in range(n)]
ary = []
ary.append(a[0])
for x in a[1:]:
	i = bisect.bisect_left(ary, x)
	if i == 0:
		ary[0:0] = [x]
	else:
		ary[i - 1:i] = [x]
print(len(ary))


import bisect
n = int(input())
a = [int(input()) for i in range(n)]
b = []
for i in range(n):
	k = bisect.bisect(b, -a[i])
	if k == len(b):
		b.append(-a[i])
	else:
		b[k] = -a[i]
print(len(b))


import sys
import bisect
input = lambda : sys.stdin.readline().rstrip()
N = int(input())
A = [int(input()) for _ in range(N)]
A = A[::-1]

def solve():
	LIS = [A[0]]
	for i in range(1, N):
		if A[i] >= LIS[-1]:
			LIS.append(A[i])
		else:
			LIS[bisect.bisect_right(LIS, A[i])] = A[i]
	ans = len(LIS)
	print(ans)

def __starting_point():
	solve()
__starting_point()


import bisect
N = int(input())
A = [int(input()) for _ in range(N)]
color = []
A = A[::-1]
for a in A:
	i = bisect.bisect_right(color, a)
	if i == len(color):
		color.append(a)
	else:
		color[i] = a
print(len(color))


import bisect
n = int(input())
x = [int(input()) for _ in range(n)]
a = [-x[0]]
l = 1
for i in range(1, n):
	b = -x[i]
	if a[-1] > b:
		if a[0] > b:
			a[0] = b
			continue
		a[bisect.bisect_right(a, b)] = b
	else:
		a.append(b)
		l += 1
print(l)


import bisect
N = int(input())
H = []
for _ in range(N):
	a = int(input())
	ind = bisect.bisect_right(H, -a)
	if ind == len(H):
		H.append(-a)
	else:
		H[ind] = -a
print(len(H))


import sys
from collections import deque
from bisect import bisect_left
sys.setrecursionlimit(10 ** 7)
input = sys.stdin.readline
f_inf = float('inf')
mod = 10 ** 9 + 7

def resolve():
	n = int(input())
	A = list((int(input()) for _ in range(n)))
	LIS = deque()
	for i in range(n):
		if len(LIS) == 0:
			LIS.appendleft(A[i])
		else:
			idx = bisect_left(LIS, A[i])
			if idx == 0:
				LIS.appendleft(A[i])
			else:
				LIS[idx - 1] = A[i]
	print(len(LIS))

def __starting_point():
	resolve()
__starting_point()


import bisect
n = int(input())
a = [int(input()) for _ in range(n)]
dp = [float('inf')] * n
for i in range(n):
	x = bisect.bisect_right(dp, -a[i])
	dp[x] = -a[i]
c = dp.count(float('inf'))
print(n - c)


from bisect import bisect
n = int(input())
seq = []
for i in range(n):
	ele = int(input())
	pos = bisect(seq, -ele)
	if len(seq) <= pos:
		seq.append(-ele)
	else:
		seq[pos] = -ele
print(len(seq))


import bisect
n = int(input())
h = []
for i in range(n):
	a = int(input())
	if len(h) == 0:
		h.append(-1 * a)
	elif -1 * a >= h[-1]:
		h.append(-1 * a)
	else:
		index = bisect.bisect_right(h, -1 * a)
		h[index] = -1 * a
print(len(h))


import bisect
n = int(input())
al = [-int(input()) for _ in range(n)]
ans = [al[0]]
for a in al[1:]:
	i = bisect.bisect(ans, a)
	if i == len(ans):
		ans.append(a)
	else:
		ans[i] = a
print(len(ans))


n = int(input())
a = [int(input()) for _ in [0] * n]
temp = []
cnt = 0
import bisect
for i in range(n):
	b = bisect.bisect(temp, -a[i])
	if b == cnt:
		temp.append(-a[i])
		cnt += 1
	else:
		temp[b] = -a[i]
print(len(temp))


import bisect
from collections import deque
N = int(input())
A = []
for _ in range(N):
	A.append(int(input()))
buf = deque()
for a in A:
	i = bisect.bisect_right(buf, a - 1) - 1
	if i < 0:
		buf.appendleft(a)
	else:
		buf[i] = a
print(len(buf))


n = int(input())
import bisect
a = [-int(input()) for _ in range(n)]
x = [a[0]]
for i in a[1:]:
	y = bisect.bisect(x, i)
	if y == len(x):
		x.append(i)
	else:
		x[y] = i
print(len(x))


import sys
import bisect

def input():
	return sys.stdin.readline().rstrip()

def main():
	n = int(input())
	A = [0] * n
	for i in range(1, n + 1):
		A[-i] = int(input())
	inf = 10 ** 10
	dp = [inf] * (n + 1)
	dp[0] = 0
	for AA in A:
		bis = bisect.bisect_right(dp, AA)
		dp[bis] = AA
	print(bisect.bisect_right(dp, inf - 100) - 1)

def __starting_point():
	main()
__starting_point()


from bisect import bisect
n = int(input())
a = [0] * n
for i in range(n):
	a[i] = -int(input())

def loopa():
	n = len(a)
	dp = [10 ** 10] * (n + 1)
	dp[0] = -10 ** 10
	for i in range(n):
		idx = bisect(dp, a[i])
		dp[idx] = min(a[i], dp[idx])
	return dp
dp = loopa()
print(bisect(dp, 10 ** 10 - 1) - 1)


import sys
input = sys.stdin.readline
import bisect
n = int(input())
a = []
for _ in range(n):
	ai = int(input()) * -1
	i = bisect.bisect_right(a, ai)
	if i == len(a):
		a.append(ai)
	else:
		a[i] = ai
print(len(a))


from bisect import bisect_left
from collections import deque
n = int(input())
A = [int(input()) for _ in range(n)]
q = deque()
for a in A:
	i = bisect_left(q, a)
	if not i:
		q.appendleft(a)
	else:
		q[i - 1] = a
print(len(q))


from bisect import bisect_left
N = int(input())
A = [int(input()) for i in range(N)]
X = [A[0]]
for i in range(1, N):
	if X[0] >= A[i]:
		X.insert(0, A[i])
	else:
		idx = bisect_left(X, A[i])
		X[idx - 1] = A[i]
print(len(X))


import sys
from bisect import bisect_left, insort_right
input = sys.stdin.readline

def main():
	N = int(input())
	A = [0] * N
	for i in range(N):
		A[i] = int(input())
	colors = []
	for a in A:
		idx = bisect_left(colors, a)
		if idx != 0:
			colors.pop(idx - 1)
		insort_right(colors, a)
	ans = len(colors)
	print(ans)

def __starting_point():
	main()
__starting_point()


import bisect
N = int(input())
A = [int(input()) for i in range(N)]
m = [-A[0]]
ans = 1
for i in A[1:]:
	p = bisect.bisect_left(m, -i + 1)
	if p == ans:
		ans += 1
		m.append(-i)
	else:
		m[p] = -i
print(ans)


import sys
import traceback
from bisect import bisect_left, bisect_right, insort
from itertools import chain, repeat, starmap
from math import log
from operator import add, eq, ne, gt, ge, lt, le, iadd
from textwrap import dedent
from collections.abc import Sequence, MutableSequence, ItemsView, KeysView, ValuesView, MutableSet, Set
from functools import wraps, reduce
from _thread import get_ident

def recursive_repr(fillvalue='...'):

	def decorating_function(user_function):
		repr_running = set()

		@wraps(user_function)
		def wrapper(self):
			key = (id(self), get_ident())
			if key in repr_running:
				return fillvalue
			repr_running.add(key)
			try:
				result = user_function(self)
			finally:
				repr_running.discard(key)
			return result
		return wrapper
	return decorating_function

class SortedList(MutableSequence):
	DEFAULT_LOAD_FACTOR = 1000

	def __init__(self, iterable=None, key=None):
		assert key is None
		self._len = 0
		self._load = self.DEFAULT_LOAD_FACTOR
		self._lists = []
		self._maxes = []
		self._index = []
		self._offset = 0
		if iterable is not None:
			self._update(iterable)

	def __new__(cls, iterable=None, key=None):
		if key is None:
			return object.__new__(cls)
		elif cls is SortedList:
			return object.__new__(SortedKeyList)
		else:
			raise TypeError('inherit SortedKeyList for key argument')

	@property
	def key(self):
		return None

	def _reset(self, load):
		values = reduce(iadd, self._lists, [])
		self._clear()
		self._load = load
		self._update(values)

	def clear(self):
		self._len = 0
		del self._lists[:]
		del self._maxes[:]
		del self._index[:]
		self._offset = 0
	_clear = clear

	def add(self, value):
		_lists = self._lists
		_maxes = self._maxes
		if _maxes:
			pos = bisect_right(_maxes, value)
			if pos == len(_maxes):
				pos -= 1
				_lists[pos].append(value)
				_maxes[pos] = value
			else:
				insort(_lists[pos], value)
			self._expand(pos)
		else:
			_lists.append([value])
			_maxes.append(value)
		self._len += 1

	def _expand(self, pos):
		_load = self._load
		_lists = self._lists
		_index = self._index
		if len(_lists[pos]) > _load << 1:
			_maxes = self._maxes
			_lists_pos = _lists[pos]
			half = _lists_pos[_load:]
			del _lists_pos[_load:]
			_maxes[pos] = _lists_pos[-1]
			_lists.insert(pos + 1, half)
			_maxes.insert(pos + 1, half[-1])
			del _index[:]
		elif _index:
			child = self._offset + pos
			while child:
				_index[child] += 1
				child = child - 1 >> 1
			_index[0] += 1

	def update(self, iterable):
		_lists = self._lists
		_maxes = self._maxes
		values = sorted(iterable)
		if _maxes:
			if len(values) * 4 >= self._len:
				values.extend(chain.from_iterable(_lists))
				values.sort()
				self._clear()
			else:
				_add = self.add
				for val in values:
					_add(val)
				return
		_load = self._load
		_lists.extend((values[pos:pos + _load] for pos in range(0, len(values), _load)))
		_maxes.extend((sublist[-1] for sublist in _lists))
		self._len = len(values)
		del self._index[:]
	_update = update

	def __contains__(self, value):
		_maxes = self._maxes
		if not _maxes:
			return False
		pos = bisect_left(_maxes, value)
		if pos == len(_maxes):
			return False
		_lists = self._lists
		idx = bisect_left(_lists[pos], value)
		return _lists[pos][idx] == value

	def discard(self, value):
		_maxes = self._maxes
		if not _maxes:
			return
		pos = bisect_left(_maxes, value)
		if pos == len(_maxes):
			return
		_lists = self._lists
		idx = bisect_left(_lists[pos], value)
		if _lists[pos][idx] == value:
			self._delete(pos, idx)

	def remove(self, value):
		_maxes = self._maxes
		if not _maxes:
			raise ValueError('{0!r} not in list'.format(value))
		pos = bisect_left(_maxes, value)
		if pos == len(_maxes):
			raise ValueError('{0!r} not in list'.format(value))
		_lists = self._lists
		idx = bisect_left(_lists[pos], value)
		if _lists[pos][idx] == value:
			self._delete(pos, idx)
		else:
			raise ValueError('{0!r} not in list'.format(value))

	def _delete(self, pos, idx):
		_lists = self._lists
		_maxes = self._maxes
		_index = self._index
		_lists_pos = _lists[pos]
		del _lists_pos[idx]
		self._len -= 1
		len_lists_pos = len(_lists_pos)
		if len_lists_pos > self._load >> 1:
			_maxes[pos] = _lists_pos[-1]
			if _index:
				child = self._offset + pos
				while child > 0:
					_index[child] -= 1
					child = child - 1 >> 1
				_index[0] -= 1
		elif len(_lists) > 1:
			if not pos:
				pos += 1
			prev = pos - 1
			_lists[prev].extend(_lists[pos])
			_maxes[prev] = _lists[prev][-1]
			del _lists[pos]
			del _maxes[pos]
			del _index[:]
			self._expand(prev)
		elif len_lists_pos:
			_maxes[pos] = _lists_pos[-1]
		else:
			del _lists[pos]
			del _maxes[pos]
			del _index[:]

	def _loc(self, pos, idx):
		if not pos:
			return idx
		_index = self._index
		if not _index:
			self._build_index()
		total = 0
		pos += self._offset
		while pos:
			if not pos & 1:
				total += _index[pos - 1]
			pos = pos - 1 >> 1
		return total + idx

	def _pos(self, idx):
		if idx < 0:
			last_len = len(self._lists[-1])
			if -idx <= last_len:
				return (len(self._lists) - 1, last_len + idx)
			idx += self._len
			if idx < 0:
				raise IndexError('list index out of range')
		elif idx >= self._len:
			raise IndexError('list index out of range')
		if idx < len(self._lists[0]):
			return (0, idx)
		_index = self._index
		if not _index:
			self._build_index()
		pos = 0
		child = 1
		len_index = len(_index)
		while child < len_index:
			index_child = _index[child]
			if idx < index_child:
				pos = child
			else:
				idx -= index_child
				pos = child + 1
			child = (pos << 1) + 1
		return (pos - self._offset, idx)

	def _build_index(self):
		row0 = list(map(len, self._lists))
		if len(row0) == 1:
			self._index[:] = row0
			self._offset = 0
			return
		head = iter(row0)
		tail = iter(head)
		row1 = list(starmap(add, zip(head, tail)))
		if len(row0) & 1:
			row1.append(row0[-1])
		if len(row1) == 1:
			self._index[:] = row1 + row0
			self._offset = 1
			return
		size = 2 ** (int(log(len(row1) - 1, 2)) + 1)
		row1.extend(repeat(0, size - len(row1)))
		tree = [row0, row1]
		while len(tree[-1]) > 1:
			head = iter(tree[-1])
			tail = iter(head)
			row = list(starmap(add, zip(head, tail)))
			tree.append(row)
		reduce(iadd, reversed(tree), self._index)
		self._offset = size * 2 - 1

	def __delitem__(self, index):
		if isinstance(index, slice):
			(start, stop, step) = index.indices(self._len)
			if step == 1 and start < stop:
				if start == 0 and stop == self._len:
					return self._clear()
				elif self._len <= 8 * (stop - start):
					values = self._getitem(slice(None, start))
					if stop < self._len:
						values += self._getitem(slice(stop, None))
					self._clear()
					return self._update(values)
			indices = range(start, stop, step)
			if step > 0:
				indices = reversed(indices)
			(_pos, _delete) = (self._pos, self._delete)
			for index in indices:
				(pos, idx) = _pos(index)
				_delete(pos, idx)
		else:
			(pos, idx) = self._pos(index)
			self._delete(pos, idx)

	def __getitem__(self, index):
		_lists = self._lists
		if isinstance(index, slice):
			(start, stop, step) = index.indices(self._len)
			if step == 1 and start < stop:
				if start == 0 and stop == self._len:
					return reduce(iadd, self._lists, [])
				(start_pos, start_idx) = self._pos(start)
				start_list = _lists[start_pos]
				stop_idx = start_idx + stop - start
				if len(start_list) >= stop_idx:
					return start_list[start_idx:stop_idx]
				if stop == self._len:
					stop_pos = len(_lists) - 1
					stop_idx = len(_lists[stop_pos])
				else:
					(stop_pos, stop_idx) = self._pos(stop)
				prefix = _lists[start_pos][start_idx:]
				middle = _lists[start_pos + 1:stop_pos]
				result = reduce(iadd, middle, prefix)
				result += _lists[stop_pos][:stop_idx]
				return result
			if step == -1 and start > stop:
				result = self._getitem(slice(stop + 1, start + 1))
				result.reverse()
				return result
			indices = range(start, stop, step)
			return list((self._getitem(index) for index in indices))
		else:
			if self._len:
				if index == 0:
					return _lists[0][0]
				elif index == -1:
					return _lists[-1][-1]
			else:
				raise IndexError('list index out of range')
			if 0 <= index < len(_lists[0]):
				return _lists[0][index]
			len_last = len(_lists[-1])
			if -len_last < index < 0:
				return _lists[-1][len_last + index]
			(pos, idx) = self._pos(index)
			return _lists[pos][idx]
	_getitem = __getitem__

	def __setitem__(self, index, value):
		message = 'use ``del sl[index]`` and ``sl.add(value)`` instead'
		raise NotImplementedError(message)

	def __iter__(self):
		return chain.from_iterable(self._lists)

	def __reversed__(self):
		return chain.from_iterable(map(reversed, reversed(self._lists)))

	def reverse(self):
		raise NotImplementedError('use ``reversed(sl)`` instead')

	def islice(self, start=None, stop=None, reverse=False):
		_len = self._len
		if not _len:
			return iter(())
		(start, stop, _) = slice(start, stop).indices(self._len)
		if start >= stop:
			return iter(())
		_pos = self._pos
		(min_pos, min_idx) = _pos(start)
		if stop == _len:
			max_pos = len(self._lists) - 1
			max_idx = len(self._lists[-1])
		else:
			(max_pos, max_idx) = _pos(stop)
		return self._islice(min_pos, min_idx, max_pos, max_idx, reverse)

	def _islice(self, min_pos, min_idx, max_pos, max_idx, reverse):
		_lists = self._lists
		if min_pos > max_pos:
			return iter(())
		if min_pos == max_pos:
			if reverse:
				indices = reversed(range(min_idx, max_idx))
				return map(_lists[min_pos].__getitem__, indices)
			indices = range(min_idx, max_idx)
			return map(_lists[min_pos].__getitem__, indices)
		next_pos = min_pos + 1
		if next_pos == max_pos:
			if reverse:
				min_indices = range(min_idx, len(_lists[min_pos]))
				max_indices = range(max_idx)
				return chain(map(_lists[max_pos].__getitem__, reversed(max_indices)), map(_lists[min_pos].__getitem__, reversed(min_indices)))
			min_indices = range(min_idx, len(_lists[min_pos]))
			max_indices = range(max_idx)
			return chain(map(_lists[min_pos].__getitem__, min_indices), map(_lists[max_pos].__getitem__, max_indices))
		if reverse:
			min_indices = range(min_idx, len(_lists[min_pos]))
			sublist_indices = range(next_pos, max_pos)
			sublists = map(_lists.__getitem__, reversed(sublist_indices))
			max_indices = range(max_idx)
			return chain(map(_lists[max_pos].__getitem__, reversed(max_indices)), chain.from_iterable(map(reversed, sublists)), map(_lists[min_pos].__getitem__, reversed(min_indices)))
		min_indices = range(min_idx, len(_lists[min_pos]))
		sublist_indices = range(next_pos, max_pos)
		sublists = map(_lists.__getitem__, sublist_indices)
		max_indices = range(max_idx)
		return chain(map(_lists[min_pos].__getitem__, min_indices), chain.from_iterable(sublists), map(_lists[max_pos].__getitem__, max_indices))

	def irange(self, minimum=None, maximum=None, inclusive=(True, True), reverse=False):
		_maxes = self._maxes
		if not _maxes:
			return iter(())
		_lists = self._lists
		if minimum is None:
			min_pos = 0
			min_idx = 0
		elif inclusive[0]:
			min_pos = bisect_left(_maxes, minimum)
			if min_pos == len(_maxes):
				return iter(())
			min_idx = bisect_left(_lists[min_pos], minimum)
		else:
			min_pos = bisect_right(_maxes, minimum)
			if min_pos == len(_maxes):
				return iter(())
			min_idx = bisect_right(_lists[min_pos], minimum)
		if maximum is None:
			max_pos = len(_maxes) - 1
			max_idx = len(_lists[max_pos])
		elif inclusive[1]:
			max_pos = bisect_right(_maxes, maximum)
			if max_pos == len(_maxes):
				max_pos -= 1
				max_idx = len(_lists[max_pos])
			else:
				max_idx = bisect_right(_lists[max_pos], maximum)
		else:
			max_pos = bisect_left(_maxes, maximum)
			if max_pos == len(_maxes):
				max_pos -= 1
				max_idx = len(_lists[max_pos])
			else:
				max_idx = bisect_left(_lists[max_pos], maximum)
		return self._islice(min_pos, min_idx, max_pos, max_idx, reverse)

	def __len__(self):
		return self._len

	def bisect_left(self, value):
		_maxes = self._maxes
		if not _maxes:
			return 0
		pos = bisect_left(_maxes, value)
		if pos == len(_maxes):
			return self._len
		idx = bisect_left(self._lists[pos], value)
		return self._loc(pos, idx)

	def bisect_right(self, value):
		_maxes = self._maxes
		if not _maxes:
			return 0
		pos = bisect_right(_maxes, value)
		if pos == len(_maxes):
			return self._len
		idx = bisect_right(self._lists[pos], value)
		return self._loc(pos, idx)
	bisect = bisect_right
	_bisect_right = bisect_right

	def count(self, value):
		_maxes = self._maxes
		if not _maxes:
			return 0
		pos_left = bisect_left(_maxes, value)
		if pos_left == len(_maxes):
			return 0
		_lists = self._lists
		idx_left = bisect_left(_lists[pos_left], value)
		pos_right = bisect_right(_maxes, value)
		if pos_right == len(_maxes):
			return self._len - self._loc(pos_left, idx_left)
		idx_right = bisect_right(_lists[pos_right], value)
		if pos_left == pos_right:
			return idx_right - idx_left
		right = self._loc(pos_right, idx_right)
		left = self._loc(pos_left, idx_left)
		return right - left

	def copy(self):
		return self.__class__(self)
	__copy__ = copy

	def append(self, value):
		raise NotImplementedError('use ``sl.add(value)`` instead')

	def extend(self, values):
		raise NotImplementedError('use ``sl.update(values)`` instead')

	def insert(self, index, value):
		raise NotImplementedError('use ``sl.add(value)`` instead')

	def pop(self, index=-1):
		if not self._len:
			raise IndexError('pop index out of range')
		_lists = self._lists
		if index == 0:
			val = _lists[0][0]
			self._delete(0, 0)
			return val
		if index == -1:
			pos = len(_lists) - 1
			loc = len(_lists[pos]) - 1
			val = _lists[pos][loc]
			self._delete(pos, loc)
			return val
		if 0 <= index < len(_lists[0]):
			val = _lists[0][index]
			self._delete(0, index)
			return val
		len_last = len(_lists[-1])
		if -len_last < index < 0:
			pos = len(_lists) - 1
			loc = len_last + index
			val = _lists[pos][loc]
			self._delete(pos, loc)
			return val
		(pos, idx) = self._pos(index)
		val = _lists[pos][idx]
		self._delete(pos, idx)
		return val

	def index(self, value, start=None, stop=None):
		_len = self._len
		if not _len:
			raise ValueError('{0!r} is not in list'.format(value))
		if start is None:
			start = 0
		if start < 0:
			start += _len
		if start < 0:
			start = 0
		if stop is None:
			stop = _len
		if stop < 0:
			stop += _len
		if stop > _len:
			stop = _len
		if stop <= start:
			raise ValueError('{0!r} is not in list'.format(value))
		_maxes = self._maxes
		pos_left = bisect_left(_maxes, value)
		if pos_left == len(_maxes):
			raise ValueError('{0!r} is not in list'.format(value))
		_lists = self._lists
		idx_left = bisect_left(_lists[pos_left], value)
		if _lists[pos_left][idx_left] != value:
			raise ValueError('{0!r} is not in list'.format(value))
		stop -= 1
		left = self._loc(pos_left, idx_left)
		if start <= left:
			if left <= stop:
				return left
		else:
			right = self._bisect_right(value) - 1
			if start <= right:
				return start
		raise ValueError('{0!r} is not in list'.format(value))

	def __add__(self, other):
		values = reduce(iadd, self._lists, [])
		values.extend(other)
		return self.__class__(values)
	__radd__ = __add__

	def __iadd__(self, other):
		self._update(other)
		return self

	def __mul__(self, num):
		values = reduce(iadd, self._lists, []) * num
		return self.__class__(values)
	__rmul__ = __mul__

	def __imul__(self, num):
		values = reduce(iadd, self._lists, []) * num
		self._clear()
		self._update(values)
		return self

	def __make_cmp(seq_op, symbol, doc):

		def comparer(self, other):
			if not isinstance(other, Sequence):
				return NotImplemented
			self_len = self._len
			len_other = len(other)
			if self_len != len_other:
				if seq_op is eq:
					return False
				if seq_op is ne:
					return True
			for (alpha, beta) in zip(self, other):
				if alpha != beta:
					return seq_op(alpha, beta)
			return seq_op(self_len, len_other)
		seq_op_name = seq_op.__name__
		comparer.__name__ = '__{0}__'.format(seq_op_name)
		doc_str = 'Return true if and only if sorted list is {0} `other`.\n        ``sl.__{1}__(other)`` <==> ``sl {2} other``\n        Comparisons use lexicographical order as with sequences.\n        Runtime complexity: `O(n)`\n        :param other: `other` sequence\n        :return: true if sorted list is {0} `other`\n        '
		comparer.__doc__ = dedent(doc_str.format(doc, seq_op_name, symbol))
		return comparer
	__eq__ = __make_cmp(eq, '==', 'equal to')
	__ne__ = __make_cmp(ne, '!=', 'not equal to')
	__lt__ = __make_cmp(lt, '<', 'less than')
	__gt__ = __make_cmp(gt, '>', 'greater than')
	__le__ = __make_cmp(le, '<=', 'less than or equal to')
	__ge__ = __make_cmp(ge, '>=', 'greater than or equal to')
	__make_cmp = staticmethod(__make_cmp)

	def __reduce__(self):
		values = reduce(iadd, self._lists, [])
		return (type(self), (values,))

	@recursive_repr()
	def __repr__(self):
		return '{0}({1!r})'.format(type(self).__name__, list(self))

	def _check(self):
		try:
			assert self._load >= 4
			assert len(self._maxes) == len(self._lists)
			assert self._len == sum((len(sublist) for sublist in self._lists))
			for sublist in self._lists:
				for pos in range(1, len(sublist)):
					assert sublist[pos - 1] <= sublist[pos]
			for pos in range(1, len(self._lists)):
				assert self._lists[pos - 1][-1] <= self._lists[pos][0]
			for pos in range(len(self._maxes)):
				assert self._maxes[pos] == self._lists[pos][-1]
			double = self._load << 1
			assert all((len(sublist) <= double for sublist in self._lists))
			half = self._load >> 1
			for pos in range(0, len(self._lists) - 1):
				assert len(self._lists[pos]) >= half
			if self._index:
				assert self._len == self._index[0]
				assert len(self._index) == self._offset + len(self._lists)
				for pos in range(len(self._lists)):
					leaf = self._index[self._offset + pos]
					assert leaf == len(self._lists[pos])
				for pos in range(self._offset):
					child = (pos << 1) + 1
					if child >= len(self._index):
						assert self._index[pos] == 0
					elif child + 1 == len(self._index):
						assert self._index[pos] == self._index[child]
					else:
						child_sum = self._index[child] + self._index[child + 1]
						assert child_sum == self._index[pos]
		except BaseException:
			traceback.print_exc(file=sys.stdout)
			print('len', self._len)
			print('load', self._load)
			print('offset', self._offset)
			print('len_index', len(self._index))
			print('index', self._index)
			print('len_maxes', len(self._maxes))
			print('maxes', self._maxes)
			print('len_lists', len(self._lists))
			print('lists', self._lists)
			raise

def identity(value):
	return value

class SortedKeyList(SortedList):

	def __init__(self, iterable=None, key=identity):
		self._key = key
		self._len = 0
		self._load = self.DEFAULT_LOAD_FACTOR
		self._lists = []
		self._keys = []
		self._maxes = []
		self._index = []
		self._offset = 0
		if iterable is not None:
			self._update(iterable)

	def __new__(cls, iterable=None, key=identity):
		return object.__new__(cls)

	@property
	def key(self):
		return self._key

	def clear(self):
		self._len = 0
		del self._lists[:]
		del self._keys[:]
		del self._maxes[:]
		del self._index[:]
	_clear = clear

	def add(self, value):
		_lists = self._lists
		_keys = self._keys
		_maxes = self._maxes
		key = self._key(value)
		if _maxes:
			pos = bisect_right(_maxes, key)
			if pos == len(_maxes):
				pos -= 1
				_lists[pos].append(value)
				_keys[pos].append(key)
				_maxes[pos] = key
			else:
				idx = bisect_right(_keys[pos], key)
				_lists[pos].insert(idx, value)
				_keys[pos].insert(idx, key)
			self._expand(pos)
		else:
			_lists.append([value])
			_keys.append([key])
			_maxes.append(key)
		self._len += 1

	def _expand(self, pos):
		_lists = self._lists
		_keys = self._keys
		_index = self._index
		if len(_keys[pos]) > self._load << 1:
			_maxes = self._maxes
			_load = self._load
			_lists_pos = _lists[pos]
			_keys_pos = _keys[pos]
			half = _lists_pos[_load:]
			half_keys = _keys_pos[_load:]
			del _lists_pos[_load:]
			del _keys_pos[_load:]
			_maxes[pos] = _keys_pos[-1]
			_lists.insert(pos + 1, half)
			_keys.insert(pos + 1, half_keys)
			_maxes.insert(pos + 1, half_keys[-1])
			del _index[:]
		elif _index:
			child = self._offset + pos
			while child:
				_index[child] += 1
				child = child - 1 >> 1
			_index[0] += 1

	def update(self, iterable):
		_lists = self._lists
		_keys = self._keys
		_maxes = self._maxes
		values = sorted(iterable, key=self._key)
		if _maxes:
			if len(values) * 4 >= self._len:
				values.extend(chain.from_iterable(_lists))
				values.sort(key=self._key)
				self._clear()
			else:
				_add = self.add
				for val in values:
					_add(val)
				return
		_load = self._load
		_lists.extend((values[pos:pos + _load] for pos in range(0, len(values), _load)))
		_keys.extend((list(map(self._key, _list)) for _list in _lists))
		_maxes.extend((sublist[-1] for sublist in _keys))
		self._len = len(values)
		del self._index[:]
	_update = update

	def __contains__(self, value):
		_maxes = self._maxes
		if not _maxes:
			return False
		key = self._key(value)
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			return False
		_lists = self._lists
		_keys = self._keys
		idx = bisect_left(_keys[pos], key)
		len_keys = len(_keys)
		len_sublist = len(_keys[pos])
		while True:
			if _keys[pos][idx] != key:
				return False
			if _lists[pos][idx] == value:
				return True
			idx += 1
			if idx == len_sublist:
				pos += 1
				if pos == len_keys:
					return False
				len_sublist = len(_keys[pos])
				idx = 0

	def discard(self, value):
		_maxes = self._maxes
		if not _maxes:
			return
		key = self._key(value)
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			return
		_lists = self._lists
		_keys = self._keys
		idx = bisect_left(_keys[pos], key)
		len_keys = len(_keys)
		len_sublist = len(_keys[pos])
		while True:
			if _keys[pos][idx] != key:
				return
			if _lists[pos][idx] == value:
				self._delete(pos, idx)
				return
			idx += 1
			if idx == len_sublist:
				pos += 1
				if pos == len_keys:
					return
				len_sublist = len(_keys[pos])
				idx = 0

	def remove(self, value):
		_maxes = self._maxes
		if not _maxes:
			raise ValueError('{0!r} not in list'.format(value))
		key = self._key(value)
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			raise ValueError('{0!r} not in list'.format(value))
		_lists = self._lists
		_keys = self._keys
		idx = bisect_left(_keys[pos], key)
		len_keys = len(_keys)
		len_sublist = len(_keys[pos])
		while True:
			if _keys[pos][idx] != key:
				raise ValueError('{0!r} not in list'.format(value))
			if _lists[pos][idx] == value:
				self._delete(pos, idx)
				return
			idx += 1
			if idx == len_sublist:
				pos += 1
				if pos == len_keys:
					raise ValueError('{0!r} not in list'.format(value))
				len_sublist = len(_keys[pos])
				idx = 0

	def _delete(self, pos, idx):
		_lists = self._lists
		_keys = self._keys
		_maxes = self._maxes
		_index = self._index
		keys_pos = _keys[pos]
		lists_pos = _lists[pos]
		del keys_pos[idx]
		del lists_pos[idx]
		self._len -= 1
		len_keys_pos = len(keys_pos)
		if len_keys_pos > self._load >> 1:
			_maxes[pos] = keys_pos[-1]
			if _index:
				child = self._offset + pos
				while child > 0:
					_index[child] -= 1
					child = child - 1 >> 1
				_index[0] -= 1
		elif len(_keys) > 1:
			if not pos:
				pos += 1
			prev = pos - 1
			_keys[prev].extend(_keys[pos])
			_lists[prev].extend(_lists[pos])
			_maxes[prev] = _keys[prev][-1]
			del _lists[pos]
			del _keys[pos]
			del _maxes[pos]
			del _index[:]
			self._expand(prev)
		elif len_keys_pos:
			_maxes[pos] = keys_pos[-1]
		else:
			del _lists[pos]
			del _keys[pos]
			del _maxes[pos]
			del _index[:]

	def irange(self, minimum=None, maximum=None, inclusive=(True, True), reverse=False):
		min_key = self._key(minimum) if minimum is not None else None
		max_key = self._key(maximum) if maximum is not None else None
		return self._irange_key(min_key=min_key, max_key=max_key, inclusive=inclusive, reverse=reverse)

	def irange_key(self, min_key=None, max_key=None, inclusive=(True, True), reverse=False):
		_maxes = self._maxes
		if not _maxes:
			return iter(())
		_keys = self._keys
		if min_key is None:
			min_pos = 0
			min_idx = 0
		elif inclusive[0]:
			min_pos = bisect_left(_maxes, min_key)
			if min_pos == len(_maxes):
				return iter(())
			min_idx = bisect_left(_keys[min_pos], min_key)
		else:
			min_pos = bisect_right(_maxes, min_key)
			if min_pos == len(_maxes):
				return iter(())
			min_idx = bisect_right(_keys[min_pos], min_key)
		if max_key is None:
			max_pos = len(_maxes) - 1
			max_idx = len(_keys[max_pos])
		elif inclusive[1]:
			max_pos = bisect_right(_maxes, max_key)
			if max_pos == len(_maxes):
				max_pos -= 1
				max_idx = len(_keys[max_pos])
			else:
				max_idx = bisect_right(_keys[max_pos], max_key)
		else:
			max_pos = bisect_left(_maxes, max_key)
			if max_pos == len(_maxes):
				max_pos -= 1
				max_idx = len(_keys[max_pos])
			else:
				max_idx = bisect_left(_keys[max_pos], max_key)
		return self._islice(min_pos, min_idx, max_pos, max_idx, reverse)
	_irange_key = irange_key

	def bisect_left(self, value):
		return self._bisect_key_left(self._key(value))

	def bisect_right(self, value):
		return self._bisect_key_right(self._key(value))
	bisect = bisect_right

	def bisect_key_left(self, key):
		_maxes = self._maxes
		if not _maxes:
			return 0
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			return self._len
		idx = bisect_left(self._keys[pos], key)
		return self._loc(pos, idx)
	_bisect_key_left = bisect_key_left

	def bisect_key_right(self, key):
		_maxes = self._maxes
		if not _maxes:
			return 0
		pos = bisect_right(_maxes, key)
		if pos == len(_maxes):
			return self._len
		idx = bisect_right(self._keys[pos], key)
		return self._loc(pos, idx)
	bisect_key = bisect_key_right
	_bisect_key_right = bisect_key_right

	def count(self, value):
		_maxes = self._maxes
		if not _maxes:
			return 0
		key = self._key(value)
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			return 0
		_lists = self._lists
		_keys = self._keys
		idx = bisect_left(_keys[pos], key)
		total = 0
		len_keys = len(_keys)
		len_sublist = len(_keys[pos])
		while True:
			if _keys[pos][idx] != key:
				return total
			if _lists[pos][idx] == value:
				total += 1
			idx += 1
			if idx == len_sublist:
				pos += 1
				if pos == len_keys:
					return total
				len_sublist = len(_keys[pos])
				idx = 0

	def copy(self):
		return self.__class__(self, key=self._key)
	__copy__ = copy

	def index(self, value, start=None, stop=None):
		_len = self._len
		if not _len:
			raise ValueError('{0!r} is not in list'.format(value))
		if start is None:
			start = 0
		if start < 0:
			start += _len
		if start < 0:
			start = 0
		if stop is None:
			stop = _len
		if stop < 0:
			stop += _len
		if stop > _len:
			stop = _len
		if stop <= start:
			raise ValueError('{0!r} is not in list'.format(value))
		_maxes = self._maxes
		key = self._key(value)
		pos = bisect_left(_maxes, key)
		if pos == len(_maxes):
			raise ValueError('{0!r} is not in list'.format(value))
		stop -= 1
		_lists = self._lists
		_keys = self._keys
		idx = bisect_left(_keys[pos], key)
		len_keys = len(_keys)
		len_sublist = len(_keys[pos])
		while True:
			if _keys[pos][idx] != key:
				raise ValueError('{0!r} is not in list'.format(value))
			if _lists[pos][idx] == value:
				loc = self._loc(pos, idx)
				if start <= loc <= stop:
					return loc
				elif loc > stop:
					break
			idx += 1
			if idx == len_sublist:
				pos += 1
				if pos == len_keys:
					raise ValueError('{0!r} is not in list'.format(value))
				len_sublist = len(_keys[pos])
				idx = 0
		raise ValueError('{0!r} is not in list'.format(value))

	def __add__(self, other):
		values = reduce(iadd, self._lists, [])
		values.extend(other)
		return self.__class__(values, key=self._key)
	__radd__ = __add__

	def __mul__(self, num):
		values = reduce(iadd, self._lists, []) * num
		return self.__class__(values, key=self._key)

	def __reduce__(self):
		values = reduce(iadd, self._lists, [])
		return (type(self), (values, self.key))

	@recursive_repr()
	def __repr__(self):
		type_name = type(self).__name__
		return '{0}({1!r}, key={2!r})'.format(type_name, list(self), self._key)

	def _check(self):
		try:
			assert self._load >= 4
			assert len(self._maxes) == len(self._lists) == len(self._keys)
			assert self._len == sum((len(sublist) for sublist in self._lists))
			for sublist in self._keys:
				for pos in range(1, len(sublist)):
					assert sublist[pos - 1] <= sublist[pos]
			for pos in range(1, len(self._keys)):
				assert self._keys[pos - 1][-1] <= self._keys[pos][0]
			for (val_sublist, key_sublist) in zip(self._lists, self._keys):
				assert len(val_sublist) == len(key_sublist)
				for (val, key) in zip(val_sublist, key_sublist):
					assert self._key(val) == key
			for pos in range(len(self._maxes)):
				assert self._maxes[pos] == self._keys[pos][-1]
			double = self._load << 1
			assert all((len(sublist) <= double for sublist in self._lists))
			half = self._load >> 1
			for pos in range(0, len(self._lists) - 1):
				assert len(self._lists[pos]) >= half
			if self._index:
				assert self._len == self._index[0]
				assert len(self._index) == self._offset + len(self._lists)
				for pos in range(len(self._lists)):
					leaf = self._index[self._offset + pos]
					assert leaf == len(self._lists[pos])
				for pos in range(self._offset):
					child = (pos << 1) + 1
					if child >= len(self._index):
						assert self._index[pos] == 0
					elif child + 1 == len(self._index):
						assert self._index[pos] == self._index[child]
					else:
						child_sum = self._index[child] + self._index[child + 1]
						assert child_sum == self._index[pos]
		except BaseException:
			traceback.print_exc(file=sys.stdout)
			print('len', self._len)
			print('load', self._load)
			print('offset', self._offset)
			print('len_index', len(self._index))
			print('index', self._index)
			print('len_maxes', len(self._maxes))
			print('maxes', self._maxes)
			print('len_keys', len(self._keys))
			print('keys', self._keys)
			print('len_lists', len(self._lists))
			print('lists', self._lists)
			raise

class SortedSet(MutableSet, Sequence):

	def __init__(self, iterable=None, key=None):
		self._key = key
		if not hasattr(self, '_set'):
			self._set = set()
		self._list = SortedList(self._set, key=key)
		_set = self._set
		self.isdisjoint = _set.isdisjoint
		self.issubset = _set.issubset
		self.issuperset = _set.issuperset
		_list = self._list
		self.bisect_left = _list.bisect_left
		self.bisect = _list.bisect
		self.bisect_right = _list.bisect_right
		self.index = _list.index
		self.irange = _list.irange
		self.islice = _list.islice
		self._reset = _list._reset
		if key is not None:
			self.bisect_key_left = _list.bisect_key_left
			self.bisect_key_right = _list.bisect_key_right
			self.bisect_key = _list.bisect_key
			self.irange_key = _list.irange_key
		if iterable is not None:
			self._update(iterable)

	@classmethod
	def _fromset(cls, values, key=None):
		sorted_set = object.__new__(cls)
		sorted_set._set = values
		sorted_set.__init__(key=key)
		return sorted_set

	@property
	def key(self):
		return self._key

	def __contains__(self, value):
		return value in self._set

	def __getitem__(self, index):
		return self._list[index]

	def __delitem__(self, index):
		_set = self._set
		_list = self._list
		if isinstance(index, slice):
			values = _list[index]
			_set.difference_update(values)
		else:
			value = _list[index]
			_set.remove(value)
		del _list[index]

	def __make_cmp(set_op, symbol, doc):

		def comparer(self, other):
			if isinstance(other, SortedSet):
				return set_op(self._set, other._set)
			elif isinstance(other, Set):
				return set_op(self._set, other)
			return NotImplemented
		set_op_name = set_op.__name__
		comparer.__name__ = '__{0}__'.format(set_op_name)
		doc_str = 'Return true if and only if sorted set is {0} `other`.\n        ``ss.__{1}__(other)`` <==> ``ss {2} other``\n        Comparisons use subset and superset semantics as with sets.\n        Runtime complexity: `O(n)`\n        :param other: `other` set\n        :return: true if sorted set is {0} `other`\n        '
		comparer.__doc__ = dedent(doc_str.format(doc, set_op_name, symbol))
		return comparer
	__eq__ = __make_cmp(eq, '==', 'equal to')
	__ne__ = __make_cmp(ne, '!=', 'not equal to')
	__lt__ = __make_cmp(lt, '<', 'a proper subset of')
	__gt__ = __make_cmp(gt, '>', 'a proper superset of')
	__le__ = __make_cmp(le, '<=', 'a subset of')
	__ge__ = __make_cmp(ge, '>=', 'a superset of')
	__make_cmp = staticmethod(__make_cmp)

	def __len__(self):
		return len(self._set)

	def __iter__(self):
		return iter(self._list)

	def __reversed__(self):
		return reversed(self._list)

	def add(self, value):
		_set = self._set
		if value not in _set:
			_set.add(value)
			self._list.add(value)
	_add = add

	def clear(self):
		self._set.clear()
		self._list.clear()

	def copy(self):
		return self._fromset(set(self._set), key=self._key)
	__copy__ = copy

	def count(self, value):
		return 1 if value in self._set else 0

	def discard(self, value):
		_set = self._set
		if value in _set:
			_set.remove(value)
			self._list.remove(value)
	_discard = discard

	def pop(self, index=-1):
		value = self._list.pop(index)
		self._set.remove(value)
		return value

	def remove(self, value):
		self._set.remove(value)
		self._list.remove(value)

	def difference(self, *iterables):
		diff = self._set.difference(*iterables)
		return self._fromset(diff, key=self._key)
	__sub__ = difference

	def difference_update(self, *iterables):
		_set = self._set
		_list = self._list
		values = set(chain(*iterables))
		if 4 * len(values) > len(_set):
			_set.difference_update(values)
			_list.clear()
			_list.update(_set)
		else:
			_discard = self._discard
			for value in values:
				_discard(value)
		return self
	__isub__ = difference_update

	def intersection(self, *iterables):
		intersect = self._set.intersection(*iterables)
		return self._fromset(intersect, key=self._key)
	__and__ = intersection
	__rand__ = __and__

	def intersection_update(self, *iterables):
		_set = self._set
		_list = self._list
		_set.intersection_update(*iterables)
		_list.clear()
		_list.update(_set)
		return self
	__iand__ = intersection_update

	def symmetric_difference(self, other):
		diff = self._set.symmetric_difference(other)
		return self._fromset(diff, key=self._key)
	__xor__ = symmetric_difference
	__rxor__ = __xor__

	def symmetric_difference_update(self, other):
		_set = self._set
		_list = self._list
		_set.symmetric_difference_update(other)
		_list.clear()
		_list.update(_set)
		return self
	__ixor__ = symmetric_difference_update

	def union(self, *iterables):
		return self.__class__(chain(iter(self), *iterables), key=self._key)
	__or__ = union
	__ror__ = __or__

	def update(self, *iterables):
		_set = self._set
		_list = self._list
		values = set(chain(*iterables))
		if 4 * len(values) > len(_set):
			_list = self._list
			_set.update(values)
			_list.clear()
			_list.update(_set)
		else:
			_add = self._add
			for value in values:
				_add(value)
		return self
	__ior__ = update
	_update = update

	def __reduce__(self):
		return (type(self), (self._set, self._key))

	@recursive_repr()
	def __repr__(self):
		_key = self._key
		key = '' if _key is None else ', key={0!r}'.format(_key)
		type_name = type(self).__name__
		return '{0}({1!r}{2})'.format(type_name, list(self), key)

	def _check(self):
		_set = self._set
		_list = self._list
		_list._check()
		assert len(_set) == len(_list)
		assert all((value in _set for value in _list))

class SortedDict(dict):

	def __init__(self, *args, **kwargs):
		if args and (args[0] is None or callable(args[0])):
			_key = self._key = args[0]
			args = args[1:]
		else:
			_key = self._key = None
		self._list = SortedList(key=_key)
		_list = self._list
		self._list_add = _list.add
		self._list_clear = _list.clear
		self._list_iter = _list.__iter__
		self._list_reversed = _list.__reversed__
		self._list_pop = _list.pop
		self._list_remove = _list.remove
		self._list_update = _list.update
		self.bisect_left = _list.bisect_left
		self.bisect = _list.bisect_right
		self.bisect_right = _list.bisect_right
		self.index = _list.index
		self.irange = _list.irange
		self.islice = _list.islice
		self._reset = _list._reset
		if _key is not None:
			self.bisect_key_left = _list.bisect_key_left
			self.bisect_key_right = _list.bisect_key_right
			self.bisect_key = _list.bisect_key
			self.irange_key = _list.irange_key
		self._update(*args, **kwargs)

	@property
	def key(self):
		return self._key

	@property
	def iloc(self):
		try:
			return self._iloc
		except AttributeError:
			warnings.warn('sorted_dict.iloc is deprecated. Use SortedDict.keys() instead.', DeprecationWarning, stacklevel=2)
			_iloc = self._iloc = SortedKeysView(self)
			return _iloc

	def clear(self):
		dict.clear(self)
		self._list_clear()

	def __delitem__(self, key):
		dict.__delitem__(self, key)
		self._list_remove(key)

	def __iter__(self):
		return self._list_iter()

	def __reversed__(self):
		return self._list_reversed()

	def __setitem__(self, key, value):
		if key not in self:
			self._list_add(key)
		dict.__setitem__(self, key, value)
	_setitem = __setitem__

	def copy(self):
		return self.__class__(self._key, self.items())
	__copy__ = copy

	@classmethod
	def fromkeys(cls, iterable, value=None):
		return cls(((key, value) for key in iterable))

	def keys(self):
		return SortedKeysView(self)

	def items(self):
		return SortedItemsView(self)

	def values(self):
		return SortedValuesView(self)

	class _NotGiven(object):

		def __repr__(self):
			return '<not-given>'
	__not_given = _NotGiven()

	def pop(self, key, default=__not_given):
		if key in self:
			self._list_remove(key)
			return dict.pop(self, key)
		else:
			if default is self.__not_given:
				raise KeyError(key)
			return default

	def popitem(self, index=-1):
		if not self:
			raise KeyError('popitem(): dictionary is empty')
		key = self._list_pop(index)
		value = dict.pop(self, key)
		return (key, value)

	def peekitem(self, index=-1):
		key = self._list[index]
		return (key, self[key])

	def setdefault(self, key, default=None):
		if key in self:
			return self[key]
		dict.__setitem__(self, key, default)
		self._list_add(key)
		return default

	def update(self, *args, **kwargs):
		if not self:
			dict.update(self, *args, **kwargs)
			self._list_update(dict.__iter__(self))
			return
		if not kwargs and len(args) == 1 and isinstance(args[0], dict):
			pairs = args[0]
		else:
			pairs = dict(*args, **kwargs)
		if 10 * len(pairs) > len(self):
			dict.update(self, pairs)
			self._list_clear()
			self._list_update(dict.__iter__(self))
		else:
			for key in pairs:
				self._setitem(key, pairs[key])
	_update = update

	def __reduce__(self):
		items = dict.copy(self)
		return (type(self), (self._key, items))

	@recursive_repr()
	def __repr__(self):
		_key = self._key
		type_name = type(self).__name__
		key_arg = '' if _key is None else '{0!r}, '.format(_key)
		item_format = '{0!r}: {1!r}'.format
		items = ', '.join((item_format(key, self[key]) for key in self._list))
		return '{0}({1}{{{2}}})'.format(type_name, key_arg, items)

	def _check(self):
		_list = self._list
		_list._check()
		assert len(self) == len(_list)
		assert all((key in self for key in _list))

def _view_delitem(self, index):
	_mapping = self._mapping
	_list = _mapping._list
	dict_delitem = dict.__delitem__
	if isinstance(index, slice):
		keys = _list[index]
		del _list[index]
		for key in keys:
			dict_delitem(_mapping, key)
	else:
		key = _list.pop(index)
		dict_delitem(_mapping, key)

class SortedKeysView(KeysView, Sequence):
	__slots__ = ()

	@classmethod
	def _from_iterable(cls, it):
		return SortedSet(it)

	def __getitem__(self, index):
		return self._mapping._list[index]
	__delitem__ = _view_delitem

class SortedItemsView(ItemsView, Sequence):
	__slots__ = ()

	@classmethod
	def _from_iterable(cls, it):
		return SortedSet(it)

	def __getitem__(self, index):
		_mapping = self._mapping
		_mapping_list = _mapping._list
		if isinstance(index, slice):
			keys = _mapping_list[index]
			return [(key, _mapping[key]) for key in keys]
		key = _mapping_list[index]
		return (key, _mapping[key])
	__delitem__ = _view_delitem

class SortedValuesView(ValuesView, Sequence):
	__slots__ = ()

	def __getitem__(self, index):
		_mapping = self._mapping
		_mapping_list = _mapping._list
		if isinstance(index, slice):
			keys = _mapping_list[index]
			return [_mapping[key] for key in keys]
		key = _mapping_list[index]
		return _mapping[key]
	__delitem__ = _view_delitem
sl = SortedList()
for i in range(int(input())):
	x = -int(input())
	ind = sl.bisect_right(x)
	if len(sl) != ind:
		sl.pop(ind)
	sl.add(x)
print(len(sl))


from bisect import *
N = int(input())
A = []
for i in range(N):
	A.append(int(input()))
r = [10 ** 10] * N
index = -1
for i in range(N):
	j = bisect_right(r, -A[i])
	r[j] = -A[i]
	if j > index:
		index = j
print(index + 1)


import math
import itertools
from collections import deque
from collections import Counter
import heapq
import bisect
n = int(input())
d = []
a = int(input()) * -1
d.append(a)
ans = 1
for i in range(n - 1):
	a = -1 * int(input())
	ind = bisect.bisect_right(d, a)
	l = len(d)
	if ind == l:
		d.append(a)
		ans += 1
	else:
		d[ind] = a
print(ans)


import bisect
n = int(input())
a = [int(input()) for i in range(n)][::-1]
color_num = [a[0]]
for i in range(1, n):
	if a[i] >= color_num[-1]:
		color_num.append(a[i])
	else:
		temp = bisect.bisect_right(color_num, a[i])
		color_num[temp] = a[i]
print(len(color_num))


import bisect
f_inf = float('inf')
n = int(input())
A = [int(input()) for _ in range(n)][::-1]
dp = [f_inf for _ in range(n + 1)]
for a in A:
	idx = bisect.bisect_right(dp, a)
	dp[idx] = a
ans = bisect.bisect_left(dp, f_inf)
print(ans)


N = int(input())
A = []
for i in range(N):
	temp = int(input())
	A.append(temp)
L = [A[0]]
for i in range(1, N):
	if L[-1] >= A[i]:
		L.append(A[i])
	elif L[0] < A[i]:
		L[0] = A[i]
	else:
		s = len(L)
		ok = s
		ng = 0
		while abs(ok - ng) > 1:
			mid = (ok + ng) // 2
			if L[mid] < A[i]:
				ok = mid
			else:
				ng = mid
		L[ok] = A[i]
ans = len(L)
print(ans)


from collections import deque
import bisect
n = int(input())
now = deque()
for _ in range(n):
	tmp = int(input())
	b = bisect.bisect_left(now, tmp)
	if b != 0:
		now[b - 1] = tmp
	else:
		now.appendleft(tmp)
print(len(now))


from bisect import bisect_left
from collections import deque
n = int(input())
ans = []
ans.append(int(input()))
ans = deque(ans)
for i in range(n - 1):
	temp = int(input())
	if temp <= ans[0]:
		ans.appendleft(temp)
	else:
		ans[bisect_left(ans, temp) - 1] = temp
print(len(ans))


import bisect
N = int(input())
A = [int(input()) for _ in range(N)]
B = []
for a in A:
	k = bisect.bisect(B, -a)
	if k == len(B):
		B.append(-a)
	else:
		B[k] = -a
print(len(B))


from bisect import bisect_left, bisect_right
from collections import deque
n = int(input())
l = []
for _ in range(n):
	a = int(input())
	l.append(a)
li = deque([l[0]])
for j in range(1, n):
	ai = l[j]
	ind = bisect_left(li, ai)
	if ind == 0:
		li.appendleft(ai)
	else:
		li[ind - 1] = ai
print(len(li))


n = int(input())
A = [int(input()) for _ in range(n)]
A.reverse()
import bisect
B = [10 ** 18]
for a in A:
	i = bisect.bisect_right(B, a)
	if 0 <= i < len(B):
		B[i] = a
	else:
		B.append(a)
print(len(B))


import bisect
N = int(input())
A = [int(input()) for _ in range(N)]
A.reverse()
dp = [A[0]]
for a in A[1:]:
	idx = bisect.bisect_right(dp, a)
	if idx == len(dp):
		dp.append(a)
	else:
		dp[idx] = a
print(len(dp))


n = int(input())
a = [int(input()) for _ in range(n)]
from bisect import bisect
b = []
for i in a:
	j = bisect(b, -i)
	if len(b) == j:
		b.append(-i)
	else:
		b[j] = -i
print(len(b))


n = int(input())
a = [int(input()) for _ in range(n)]
from bisect import bisect
h = []
for ai in a:
	ix = bisect(h, -ai)
	if ix == len(h):
		h.append(-ai)
	else:
		h[ix] = -ai
print(len(h))


def bisect_right_reverse(a, x):
	if a[0] < x:
		return 0
	if x <= a[-1]:
		return len(a)
	ok = len(a) - 1
	ng = 0
	while abs(ok - ng) > 1:
		mid = (ok + ng) // 2
		if a[mid] < x:
			ok = mid
		else:
			ng = mid
	return ok

def main():
	N = int(input())
	ans = 1
	lis_min = [int(input())]
	for i in range(N - 1):
		a = int(input())
		index = bisect_right_reverse(lis_min, a)
		if index != len(lis_min):
			lis_min[index] = a
		else:
			ans += 1
			lis_min.append(a)
	print(ans)

def __starting_point():
	main()
__starting_point()


import bisect
N = int(input())
A = [-int(input()) for _ in range(N)]
p = [A[0]]
for i in A[1:]:
	if p[-1] <= i:
		p.append(i)
	else:
		p[bisect.bisect_right(p, i)] = i
print(len(p))


from bisect import bisect_right

def main():
	inf = float('inf')
	n = int(input())
	alst = [int(input()) for _ in range(n)]
	work = [inf] * n
	for i in range(n - 1, -1, -1):
		j = bisect_right(work, alst[i])
		work[j] = alst[i]
	print(n - work.count(inf))
main()


from bisect import bisect_right
(N, *A) = map(int, open(0).read().split())
INF = 10 ** 10
dp = [INF] * N
for i in range(N):
	dp[bisect_right(dp, -A[i])] = -A[i]
print(max((i + 1 for (i, v) in enumerate(dp) if v < INF)))


import bisect
n = int(input())
a = [-int(input()) for i in range(n)]
tmp = [a[0]]
for i in range(1, n):
	idx = bisect.bisect_right(tmp, a[i])
	if idx == len(tmp):
		tmp.append(a[i])
	else:
		tmp[idx] = a[i]
print(len(tmp))


from collections import deque
from bisect import bisect_left
N = int(input())
d = deque()
for i in range(N):
	A = int(input())
	b = bisect_left(d, A) - 1
	if b == -1:
		d.appendleft(A)
	else:
		d[b] = A
print(len(d))


import bisect
n = int(input())
ans = 0
mylist = []
for i in range(n):
	k = int(input())
	idx = bisect.bisect(mylist, -k)
	if idx == ans:
		mylist.append(-k)
		ans += 1
	else:
		mylist[idx] = -k
print(ans)


from bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)]
arr = []
l = 0
for a in A:
	a = -a
	idx = bisect_right(arr, a)
	if idx == l:
		arr.append(a)
		l += 1
	else:
		arr[idx] = a
print(l)


import bisect
from collections import deque
n = int(input())
c = deque()
for i in range(n):
	a = int(input())
	idx = bisect.bisect_left(c, a)
	if idx == 0:
		c.appendleft(a)
	else:
		c[idx - 1] = a
print(len(c))


import math, itertools, fractions, heapq, collections, bisect, sys, queue, copy
sys.setrecursionlimit(10 ** 7)
inf = 10 ** 20
mod = 10 ** 9 + 7
dd = [(-1, 0), (0, 1), (1, 0), (0, -1)]
ddn = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]

def LI():
	return [int(x) for x in sys.stdin.readline().split()]

def I():
	return int(sys.stdin.readline())

def F():
	return float(sys.stdin.readline())

def LS():
	return sys.stdin.readline().split()

def S():
	return input()

def main():
	n = I()
	_l = [I() for _ in range(n)]
	l = collections.deque()
	for A in _l:
		if len(l) == 0:
			l.append(A)
			continue
		lv = l[0]
		rv = l[-1]
		if rv < A:
			l[-1] = A
			continue
		if A <= lv:
			l.appendleft(A)
			continue
		li = 0
		ri = len(l) - 1
		while ri - li > 1:
			mi = (ri + li) // 2
			if l[mi] < A:
				li = mi
			else:
				ri = mi
		l[li] = A
	return len(l)
print(main())


from collections import deque
from bisect import bisect_left
N = int(input())
li = []
ans = 0
for i in range(N):
	a = -int(input())
	b = bisect_left(li, a + 1)
	if b == len(li):
		li.append(a)
		ans += 1
	else:
		li[b] = a
print(ans)


N = int(input())
A = [int(input()) for _ in range(N)]
import bisect
B = [A[N - 1]]
for i in range(N - 2, -1, -1):
	if A[i] >= B[-1]:
		B.append(A[i])
	else:
		B[bisect.bisect_right(B, A[i])] = A[i]
print(len(B))


import sys
from bisect import bisect_right
INF = float('inf')

def main():
	N = int(input())
	A = [int(input()) for _ in range(N)]
	dp = [INF] * N
	for i in range(N):
		j = bisect_right(dp, -A[i])
		dp[j] = -A[i]
	print(sum([1 for d in dp if d < INF]))

def __starting_point():
	main()
__starting_point()


import bisect
from collections import deque
n = int(input())
l = deque([int(input())])
for i in range(1, n):
	a = int(input())
	p = bisect.bisect_left(l, a)
	if p == 0:
		l.appendleft(a)
	else:
		l[p - 1] = a
print(len(l))


n = int(input())
c = []
hc = 0
for i in range(n):
	a = int(input())
	(l, r) = (-1, hc)
	while r - l != 1:
		t = (l + r) // 2
		if c[t] < a:
			r = t
		else:
			l = t
	if r == hc:
		c.append(a)
		hc += 1
	else:
		c[r] = a
print(hc)


N = int(input())
A = [int(input()) for i in range(N)]
from bisect import *
h = []
for a in A:
	x = bisect_right(h, -a)
	if len(h) <= x:
		h.append(-a)
	else:
		h[x] = -a
result = len(h)
print(result)


from collections import deque
import bisect
n = int(input())
dq = deque()
for i in range(n):
	a = int(input())
	index = bisect.bisect_left(dq, a)
	if index == 0:
		dq.appendleft(a)
	else:
		dq[index - 1] = a
print(len(dq))


from bisect import bisect_right
(N, *A) = map(int, open(0).read().split())
A.reverse()
dp = [A[0]]
for a in A[1:]:
	if dp[-1] <= a:
		dp.append(a)
	else:
		dp[bisect_right(dp, a)] = a
print(len(dp))


import bisect
n = int(input())
li = [int(input()) for i in range(n)]
li = [-x for x in li]
X = []
X.append(li[0])
for i in range(1, n):
	idx = bisect.bisect_right(X, li[i])
	if idx == len(X):
		X.append(li[i])
	else:
		X[idx] = li[i]
print(len(X))


import bisect
n = int(input())
a = [int(input()) for i in range(n)]
inf = 10 ** 9 + 1
tmp = [inf] * n
ans = 0
for i in range(n - 1, -1, -1):
	j = bisect.bisect_right(tmp, a[i])
	tmp[j] = a[i]
for i in range(n):
	if tmp[i] != inf:
		ans += 1
print(ans)


from bisect import bisect_right as br
INF = 10 ** 10
n = int(input())
alst = [int(input()) for _ in range(n)][::-1]
dp = [INF] * (n + 1)
dp[0] = -1
ans = 0
for a in alst:
	ind = br(dp, a)
	dp[ind] = a
	ans = max(ans, ind)
print(ans)


n = int(input())
a = [int(input()) for _ in range(n)]
ans = [-a[0]]
ansl = 1
from bisect import bisect_right
for ai in a[1:]:
	tmp = bisect_right(ans, -ai)
	if tmp < ansl:
		ans[tmp] = -ai
	else:
		ans.append(-ai)
		ansl += 1
print(ansl)


import sys
input = sys.stdin.readline
from bisect import bisect_left, bisect_right

def read():
	N = int(input().strip())
	A = [int(input().strip()) for _ in range(N)]
	return (N, A)

def solve(N, A, INF=10 ** 9 + 1):
	dp = [INF for i in range(N)]
	for i in range(N):
		a = A[N - i - 1]
		idx = bisect_right(dp, a)
		dp[idx] = a
	return bisect_right(dp, INF - 1)

def __starting_point():
	inputs = read()
	outputs = solve(*inputs)
	if outputs is not None:
		print('%s' % str(outputs))
__starting_point()


from bisect import bisect_right
n = int(input())
a = [int(input()) for _ in range(n)]
a = a[::-1]
lis = [a[0]]
for i in range(1, n):
	if lis[-1] <= a[i]:
		lis.append(a[i])
	else:
		inde = bisect_right(lis, a[i])
		lis[inde] = a[i]
print(len(lis))


from bisect import bisect
n = int(input())
A = [int(input()) for i in range(n)]
ans = []
for a in A:
	i = bisect(ans, -a)
	if len(ans) == i:
		ans.append(-a)
	elif -a < ans[i]:
		ans[i] = -a
print(len(ans))


from bisect import bisect
N = int(input())
A = [int(input()) for _ in range(N)]
INF = 10 ** 10
dp = [-INF]
for a in A:
	if a <= -dp[-1]:
		dp.append(-a)
	else:
		i = bisect(dp, -a)
		dp[i] = -a
ans = len(dp) - 1
print(ans)


N = int(input())
A = [int(input()) for i in range(N)]
import bisect
B = []
C = A[::-1]
for i in C:
	a = bisect.bisect_right(B, i)
	if a == len(B):
		B.append(i)
	else:
		B[a] = i
print(len(B))


from collections import deque
from bisect import bisect_left

def main():
	(N, *A) = map(int, open(0))
	q = deque([])
	for i in range(N):
		d = bisect_left(q, A[i])
		if d == 0:
			q.appendleft(A[i])
		else:
			q[d - 1] = A[i]
	print(len(q))

def __starting_point():
	main()
__starting_point()


import bisect
inf = 1000000009
n = int(input())
a = [int(input()) for i in range(n)]
b = [inf] * (n + 10)
for i in range(n):
	j = bisect.bisect_right(b, -a[i], 0, hi=len(b))
	b[j] = -a[i]
print(bisect.bisect_left(b, inf, 0, hi=len(b)))


import sys
N = int(input())
now = int(sys.stdin.readline().strip())
ans = [now]
for n in range(N - 1):
	now = int(sys.stdin.readline().strip())
	if now > ans[0]:
		ans[0] = now
	elif ans[-1] >= now:
		ans.append(now)
	else:
		left = 0
		right = len(ans) - 1
		while right - left > 1:
			mid = (right + left) // 2
			if now > ans[mid]:
				right = mid
			else:
				left = mid
		ans[right] = now
print(len(ans))


from _bisect import bisect_right
N = int(input())
A = [int(input()) for _ in range(N)][::-1]
DP = [A[0]]
for i in range(1, N):
	num = A[i]
	if num >= DP[-1]:
		DP.append(num)
	else:
		index = bisect_right(DP, num)
		DP[index] = num
print(len(DP))


from bisect import bisect
import heapq
N = int(input())
A = [int(input()) for _ in range(N)]
q = []
A.reverse()
for i in range(N):
	ii = bisect(q, A[i])
	if ii == len(q):
		heapq.heappush(q, A[i])
	else:
		q[ii] = A[i]
print(len(q))


from bisect import bisect
n = int(input())
vals = []
for _ in range(n):
	a = -int(input())
	idx = bisect(vals, a)
	if idx == len(vals):
		vals.append(a)
	else:
		vals[idx] = a
print(len(vals))


from collections import deque
from bisect import bisect_left
N = int(input())
que = deque()
ans = 0
for i in range(N):
	a = int(input())
	b = bisect_left(que, a)
	if b - 1 < 0:
		que.appendleft(a)
		ans += 1
	else:
		que[b - 1] = a
print(ans)


import bisect, collections
n = int(input())
num = collections.deque([])
for i in range(n):
	a = int(input())
	temp = bisect.bisect_left(num, a)
	if temp == 0:
		num.appendleft(a)
	else:
		num[temp - 1] = a
print(len(num))


N = int(input())
from collections import deque
d = deque([int(input())])
import bisect
for i in range(N - 1):
	a = int(input())
	if a > d[-1]:
		d[-1] = a
	elif d[0] >= a:
		d.appendleft(a)
	else:
		i = bisect.bisect_left(d, a)
		d[i - 1] = a
print(len(d))


from bisect import bisect_right

def main():
	n = int(input())
	a = [int(input()) for _ in range(n)]
	a.reverse()
	lis = [a[0]]
	for i in range(1, n):
		if a[i] >= lis[-1]:
			lis.append(a[i])
		else:
			lis[bisect_right(lis, a[i])] = a[i]
	print(len(lis))

def __starting_point():
	main()
__starting_point()


def binary_search(key):
	(bad, good) = (-1, len(ans))
	while good - bad > 1:
		mid = (bad + good) // 2
		if ans[mid][-1] < key:
			good = mid
		else:
			bad = mid
	return good
N = int(input())
ans = []
for _ in range(N):
	A = int(input())
	idx = binary_search(A)
	if idx == len(ans):
		ans.append([A])
	else:
		ans[idx].append(A)
print(len(ans))


from bisect import bisect_left, bisect
n = int(input())
p = [-1 * int(input())]
for i in range(n - 1):
	now = -1 * int(input())
	if now >= p[-1]:
		p.append(now)
	else:
		p[bisect(p, now)] = now
print(len(p))


from bisect import bisect_left
N = int(input())
A = []
for _ in range(N):
	x = int(input())
	idx = bisect_left(A, x)
	if idx == 0:
		A.insert(idx, x)
	elif A[idx - 1] == x:
		A.insert(idx, x)
	else:
		A[idx - 1] = x
print(len(A))


from collections import deque
from bisect import bisect_left
n = int(input())
a = [int(input()) for _ in range(n)]
dp = deque([])
b = []
for i in range(n):
	j = bisect_left(dp, a[i])
	if j == 0:
		dp.appendleft(a[i])
	else:
		dp[j - 1] = a[i]
print(len(dp))


from bisect import bisect_left
n = int(input())
a = [int(input()) for i in range(n)]
dp = [-float('inf')] * (n + 1)
for i in a:
	dp[bisect_left(dp, i) - 1] = i
print(dp[::-1].index(-float('inf')))


n = int(input())
a = [int(input()) * -1 for _ in range(n)]
inf = 10 ** 10
l = [inf] * n
import bisect
for i in range(n):
	r = bisect.bisect_right(l, a[i])
	l[r] = a[i]
cnt = 0
for i in range(n):
	if l[i] != inf:
		cnt += 1
	else:
		break
print(cnt)


from bisect import bisect_right
n = int(input())
a = [-int(input()) for _ in range(n)]
lst = [a[0]]
for aa in a[1:]:
	i = bisect_right(lst, aa)
	if i == len(lst):
		lst.append(aa)
	else:
		lst[i] = aa
print(len(lst))


from bisect import bisect_left, bisect_right
N = int(input())
As = [int(input()) for _ in range(N)]
dp = [float('inf')] * (N + 1)
for A in reversed(As):
	i = bisect_right(dp, A)
	dp[i] = A
print(dp.index(float('inf')))


import bisect
n = int(input())
c = []
for i in range(n):
	a = int(input())
	j = bisect.bisect_right(c, -a)
	if j == len(c):
		c.append(-a)
	else:
		c[j] = -a
print(len(c))


import bisect
n = int(input())
A = [int(input()) for i in range(n)]
m = 10 ** 9
X = []
for a in A:
	i = bisect.bisect_right(X, -a)
	if i == len(X):
		X.append(-a)
	else:
		X[i] = -a
print(len(X))


from bisect import *

def solve():
	ans = 0
	N = int(input())
	A = [-int(input()) for _ in range(N)]
	lis = [A[0]]
	for i in range(1, N):
		if A[i] >= lis[-1]:
			lis.append(A[i])
		else:
			ind = bisect_right(lis, A[i])
			lis[ind] = A[i]
	ans = len(lis)
	return ans
print(solve())


from bisect import bisect_right
import sys
input = sys.stdin.buffer.readline
N = int(input())
A = [int(input()) for _ in range(N)]
dp = [10 ** 10] * N
for a in A:
	a = -a
	dp[bisect_right(dp, a)] = a
ans = N - dp.count(10 ** 10)
print(ans)


from bisect import bisect_right
N = int(input())
X = [int(input()) for _ in range(N)]
INF = 10 ** 9 + 7
dp = [INF] * (N + 1)
for i in range(N):
	dp[bisect_right(dp, -X[i])] = -X[i]
print(sum((v < INF for v in dp)))


import sys
from bisect import bisect_right
input = sys.stdin.readline

def main():
	N = int(input())
	A = [0] * N
	for i in range(N):
		A[i] = int(input())
	A = [-a for a in A]
	colors = []
	for a in A:
		idx = bisect_right(colors, a)
		if idx == len(colors):
			colors.append(a)
		else:
			colors[idx] = a
	ans = len(colors)
	print(ans)

def __starting_point():
	main()
__starting_point()


N = int(input())
A = [int(input()) for _ in range(N)]

def solve(A, n):
	import bisect
	dp = [float('inf')] * n
	for i in range(n - 1, -1, -1):
		k = bisect.bisect_right(dp, A[i])
		dp[k] = A[i]
	ans = 0
	for a in dp:
		if a != float('inf'):
			ans += 1
		else:
			break
	return ans
print(solve(A, N))


N = int(input())
A = [int(input()) for _ in range(N)][::-1]

def LIS(L):
	from bisect import bisect
	seq = []
	for i in L:
		pos = bisect(seq, i)
		if len(seq) <= pos:
			seq.append(i)
		else:
			seq[pos] = i
	return len(seq)
print(LIS(A))