### BUGGY CODE ###

import sys
input = sys.stdin.readline
from heapq import heappush, heappop


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


class SegmentTree():
    
    def __init__(self, size, init_value=10**8):
        """初期化"""
        self.size = size
        self.init_value = init_value
        n = 2 ** ((size-1).bit_length())
        treesize = n * 2
        st = [init_value] * treesize
        st_idx = [i for i in range(treesize)]
        self.st = st
        self.st_idx = st_idx
        self.offset = len(st) // 2

    @classmethod
    def from_array(cls, a, init_value=10**8):
        st = cls(len(a), init_value=init_value)
        for i, x in enumerate(a):
            st.update(i, x)
        return st

    def update(self, key, value):
        """値の更新"""
        k = self.offset + key
        self.st[k] = value
        k >>= 1
        while k > 0:
            if self.st[k * 2] <= self.st[k * 2 + 1]:
                self.st[k] = self.st[k * 2]
                self.st_idx[k] = self.st_idx[k * 2]
            else:
                self.st[k] = self.st[k * 2 + 1]
                self.st_idx[k] = self.st_idx[k * 2 + 1]
            k >>= 1

    def _smallest(self, a, b):
        """区間[a, b) の最小値を検索し、(index, value)の組を返す
        """
        a += self.offset
        b += self.offset - 1
        s = self.init_value
        idx = -1
        while a < b:
            if a & 1:
                if self.st[a] <= s:
                    s = self.st[a]
                    idx = self.st_idx[a]
                a += 1
            a >>= 1
            if not b & 1:
                if self.st[b] <= s:
                    s = self.st[b]
                    idx = self.st_idx[b]
                b -= 1
            b >>= 1
        if a == b:
            if self.st[a] <= s:
                s = self.st[a]
                idx = self.st_idx[a]
        return idx - self.offset, s

    def smallest(self, a, b):
        """区間[a, b) に対する累積操作"""
        if a > b:
            raise ValueError("a must be less than equal b.")
        return self._smallest(a, b)
    
    def _find_le(self, value, k=1):
        """value以下の最大の値を検索し、(index, value)の組を返す
        k: 着目しているノード (1-indexed)
        l: 探索区間 st[l, r) の左端 (0-indexed)
        r: 探索区間 st[l, r) の右端 (0-indexed)
        """
        if value < self.st[k]:
            return (len(self.st), -self.init_value)
        elif value == self.st[k] or k >= self.offset:
            return (self.st_idx[k], self.st[k])
        else:
            li, lv = self._find_le(value, k * 2)
            ri, rv = self._find_le(value, k * 2 + 1)
            mi = li if lv >= rv else ri
            mv = lv if lv >= rv else rv
            if mi < len(self.st):
                return (mi, mv)
            else:
                return (len(self.st), -self.init_value)
    
    def find_le(self, value):
        """value以下の最大値を検索し、(index, value)の組を1つ返す
        見つからない場合は-1を返す
        """
        i, v = self._find_le(value, k=1)
        if i == len(self.st):
            return (-1, self.init_value)
        else:
            return (i - self.offset, v)


def solve(N, A, INF=10**9+1):
    st = SegmentTree(N)
    l = 0
    for a in A[::-1]:
        k, v = st.find_le(-a-1)  # 以下を未満にするため-1
        if k == -1:
            st.update(l, -a)
            l += 1
        else:
            st.update(k, -a)
    return l


if __name__ == '__main__':
    inputs = read()
    outputs = solve(*inputs)
    if outputs is not None:
        print("%s" % str(outputs))


### FIXED CODE ###

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):
    # LIS
    # dp[i]: 長さiの最長増加部分列(A[i]<A[j])のうち、最も小さい数字
    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)


if __name__ == '__main__':
    inputs = read()
    outputs = solve(*inputs)
    if outputs is not None:
        print("%s" % str(outputs))