Problem:
Score : 500 points

Problem Statement

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 1

5
2
1
4
5
3

Sample Output 1

2

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

Sample Input 2

4
0
0
0
0

Sample Output 2

4

We have to paint all the integers with distinct colors.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
        Console.SetOut(sw);

        var N = sc.ReadInt();
        var A = sc.ReadIntArray(N);
        var t = new Treap<int>();
        for (int i = 0; i < N; i++)
        {
            var a = A[i];
            var index = t.LowerBouond(a) - 1;
            if (0 <= index && index < t.Length)
            {
                t.Erase(t[index]);
            }
            t.Insert(a);
        }
        var ans = t.Length;
        Console.WriteLine(ans);

        Console.Out.Flush();
    }

    static Scanner sc = new Scanner();
}

class Treap<T>
{
    public int Length
    {
        get { return this.Root == null ? 0 : this.NodeCount(this.Root); }
    }
    public T this[int i]
    {
        get
        {
            if (this.Root.Count < i - 1) throw new IndexOutOfRangeException();
            return this.Root.Get(i);
        }
    }
    public Node Root;
    private IComparer<T> Cmp = Comparer<T>.Default;
    public Treap(IComparer<T> cmp = null)
    {
        if (cmp != null) this.Cmp = cmp;
    }
    public Node Merge(Node l, Node r)
    {
        if (l == null || r == null) return l == null ? r : l;

        if (l.Priority > r.Priority)
        {
            l.R = this.Merge(l.R, r);
            return this.Update(l);
        }
        else
        {
            r.L = this.Merge(l, r.L);
            return this.Update(r);
        }
    }
    public Tuple<Node, Node> Split(int k) { return this.Split(this.Root, k); }
    public Tuple<Node, Node> Split(Node t, int k)
    {
        if (t == null) return Tuple.Create<Node, Node>(null, null);
        if (k <= this.NodeCount(t.L))
        {
            var s = this.Split(t.L, k);
            t.L = s.Item2;
            return Tuple.Create(s.Item1, this.Update(t));
        }
        else
        {
            var s = this.Split(t.R, k - this.NodeCount(t.L) - 1);
            t.R = s.Item1;
            return Tuple.Create(this.Update(t), s.Item2);
        }
    }
    public Node Update(Node node)
    {
        node.Count = this.NodeCount(node.L) + this.NodeCount(node.R) + 1;
        return node;
    }
    public int NodeCount(Node node)
    {
        return node == null ? 0 : node.Count;
    }
    public int LowerBouond(T value) { return this.LowerBouond(this.Root, value); }
    public int LowerBouond(Node node, T value)
    {
        if (node == null) return 0;
        if (this.Cmp.Compare(value, node.Value) <= 0)
            return this.LowerBouond(node.L, value);
        else
            return this.NodeCount(node.L) + 1 + this.LowerBouond(node.R, value);
    }
    public int UpperBound(T value) { return this.UpperBound(this.Root, value); }
    public int UpperBound(Node node, T value)
    {
        if (node == null) return 0;
        if (this.Cmp.Compare(value, node.Value) >= 0)
            return this.NodeCount(node.L) + 1 + this.UpperBound(node.R, value);
        else
            return this.UpperBound(node.L, value);
    }
    public int ValueCount(T value)
    {
        return this.UpperBound(value) - this.LowerBouond(value);
    }
    public void Insert(T value)
    {
        var sub = this.Split(this.Root, this.LowerBouond(value));
        var newNode = new Node(value);
        var merged = this.Merge(sub.Item1, newNode);
        this.Root = this.Merge(merged, sub.Item2);
    }
    public void Erase(T value)
    {
        if (this.ValueCount(value) == 0) return;
        var sub = this.Split(this.Root, this.LowerBouond(value));
        this.Root = this.Merge(sub.Item1, this.Split(sub.Item2, 1).Item2);
    }
    public class Node
    {
        private static Random Rand = new Random();
        public T Value { get; set; }
        public Node L { get; set; } = null;
        public Node R { get; set; } = null;
        public int Count { get; set; }
        public double Priority { get; set; }
        public Node(T value, double priority)
        {
            this.Value = value;
            this.Priority = priority;
            this.Count = 1;
        }
        public Node(T value) : this(value, Rand.NextDouble()) { }
        public T Get(int i)
        {
            var lcount = 0;
            if (this.L != null) lcount = this.L.Count;
            if (lcount == i) return this.Value;
            else if (lcount < i) return this.R.Get(i - lcount - 1);
            else return this.L.Get(i);
        }
    }
}

class Scanner
{
    string[] S = new string[0];
    int Index = 0;
    char[] Separators = new char[] { ' ' };

    public string Next()
    {
        if (this.Index < this.S.Length) return this.S[this.Index++];
        var line = "";
        while (line == "") line = Console.ReadLine();
        this.S = line.Split(this.Separators, StringSplitOptions.RemoveEmptyEntries);
        if (this.S.Length == 0) return this.Next();
        this.Index = 0;
        return this.S[this.Index++];
    }
    public string ReadStr()
    {
        return this.Next();
    }
    public char ReadChar()
    {
        return this.Next()[0];
    }
    public int ReadInt()
    {
        return int.Parse(this.Next());
    }
    public uint ReadUInt()
    {
        return uint.Parse(this.Next());
    }
    public long ReadLong()
    {
        return long.Parse(this.Next());
    }
    public double ReadDouble()
    {
        return double.Parse(this.Next());
    }
    public Tuple<int, int> ReadTup(int add = 0)
    {
        return Tuple.Create(this.ReadInt() + add, this.ReadInt() + add);
    }
    public Tuple<long, long> ReadTupLong(int add = 0)
    {
        return Tuple.Create(this.ReadLong() + add, this.ReadLong() + add);
    }
    public Tuple<int, int, int> ReadTup3(int add = 0)
    {
        return Tuple.Create(this.ReadInt() + add, this.ReadInt() + add, this.ReadInt() + add);
    }
    public Tuple<int, int, int, int> ReadTup4(int add = 0)
    {
        return Tuple.Create(this.ReadInt() + add, this.ReadInt() + add, this.ReadInt() + add, this.ReadInt() + add);
    }
    public int[] ReadIntArray(int n)
    {
        var array = new int[n];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = this.ReadInt();
        }
        return array;
    }
    public long[] ReadLongArray(int n)
    {
        var array = new long[n];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = this.ReadLong();
        }
        return array;
    }
    public double[] ReadDoubleArray(int n)
    {
        var array = new double[n];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = this.ReadDouble();
        }
        return array;
    }
    public char[] ReadCharArray(int n)
    {
        var array = new char[n];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = this.ReadChar();
        }
        return array;
    }
    public string[] ReadStrArray(int n)
    {
        var array = new string[n];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = this.ReadStr();
        }
        return array;
    }
    public Tuple<long, long>[] ReadTupLongArray(int n, int add = 0)
    {
        var array = new Tuple<long, long>[n];
        for (int i = 0; i < n; i++)
        {
            array[i] = this.ReadTupLong(add);
        }
        return array;
    }
    public Tuple<int, int>[] ReadTupArray(int n, int add = 0)
    {
        var array = new Tuple<int, int>[n];
        for (int i = 0; i < n; i++)
        {
            array[i] = this.ReadTup(add);
        }
        return array;
    }
    public Tuple<int, int, int>[] ReadTup3Array(int n, int add = 0)
    {
        var array = new Tuple<int, int, int>[n];
        for (int i = 0; i < n; i++)
        {
            array[i] = this.ReadTup3(add);
        }
        return array;
    }
    public Tuple<int, int, int, int>[] ReadTup4Array(int n, int add = 0)
    {
        var array = new Tuple<int, int, int, int>[n];
        for (int i = 0; i < n; i++)
        {
            array[i] = this.ReadTup4(add);
        }
        return array;
    }
}