#include <bits/stdc++.h>
using namespace std;
ifstream fin ("scmax.in");
ofstream fout ("scmax.out");
const int maxDim = 1e5 + 1 , INF = 1e9;
int N , K , a[maxDim] , b[maxDim] , dp[maxDim] , prevv[maxDim];
unordered_map <int , int> poz , poz1;
struct Elem
{
int v;
int p;
}seg_tree[4 * maxDim];
class ST
{
private:
void Update_Node (int node)
{
if(seg_tree[2 * node].v > seg_tree[2 * node + 1].v)
{
seg_tree[node].v = seg_tree[2 * node].v;
seg_tree[node].p = seg_tree[2 * node].p;
}
else
{
seg_tree[node].v = seg_tree[2 * node + 1].v;
seg_tree[node].p = seg_tree[2 * node + 1].p;
}
}
void Update (int node , int l , int r , int p , int R)
{
if(l == r)
{
if(seg_tree[node].v < R)
seg_tree[node].v = R , seg_tree[node].p = p;
}
else
{
int m = (l + r) / 2;
if(p <= m)
Update(2 * node , l , m , p , R);
else
Update(2 * node + 1 , m + 1 , r , p , R);
Update_Node(node);
}
}
pair<int , int> Query (int node , int l , int r , int l1 , int r1)
{
if(l >= l1 && r <= r1)
return make_pair(seg_tree[node].v , seg_tree[node].p);
else
{
int m = (l + r) / 2;
if(r1 <= m)
return Query(2 * node , l , m , l1 , r1);
else if(l1 > m)
return Query(2 * node + 1 , m + 1 , r , l1 , r1);
else
{
pair<int , int> A , B;
A = Query(2 * node , l , m , l1 , r1);
B = Query(2 * node + 1 , m + 1 , r , l1 , r1);
if(A.first > B.first)
return A;
return B;
}
}
}
public:
void Update (int p , int val)
{
Update(1 , 1 , N , p , val);
}
pair<int,int> Query1(int p)
{
return Query(1 , 1 , N , 1 , p);
}
};
void Drum (int p)
{
if(prevv[p])
Drum(prevv[p]);
cout << a[p] << " ";
}
int main()
{
fin >> N;
for (int i = 1; i <= N; ++i)
{
fin >> a[i];
b[i] = a[i];
}
sort (b + 1 , b + N + 1);
for (int i = 1; i <= N; ++i)
if(!poz[b[i]])
poz[b[i]] = ++K;
ST SGT;
dp[1] = 1;
SGT.Update(poz[a[1]] , 1);
int P = 1;
for (int i = 2; i <= N; ++i)
{
pair <int , int> T;
if(poz[a[i]] != 1)
{
T = SGT.Query1(poz[a[i]] - 1);
dp[i] = 1 + T.first;
prevv[i] = poz1[T.second];
SGT.Update(poz[a[i]] , dp[i]);
}
else
{
dp[i] = 1;
SGT.Update(poz[a[i]] , 1);
}
if(dp[i] > dp[P])
P = i;
}
fout << dp[P] << "\n";
}