#include <iostream>
#include <vector>
// Binary search (note boundaries in the caller)
int CeilIndex(std::vector<int>& v, int l, int r, int key)
{
while (r - l > 1) {
int m = l + (r - l) / 2;
if (v[m] >= key)
r = m;
else
l = m;
}
return r;
}
int LongestIncreasingSubsequenceLength(std::vector<int>& v)
{
if (v.size() == 0)
return 0;
std::vector<int> tail(v.size(), 0);
int length = 1; // always points empty slot in tail
tail[0] = v[0];
for (size_t i = 1; i < v.size(); i++) {
// new smallest value
if (v[i] < tail[0])
tail[0] = v[i];
// v[i] extends largest subsequence
else if (v[i] > tail[length - 1])
tail[length++] = v[i];
// v[i] will become end candidate of an existing
// subsequence or Throw away larger elements in all
// LIS, to make room for upcoming greater elements
// than v[i] (and also, v[i] would have already
// appeared in one of LIS, identify the location
// and replace it)
else
tail[CeilIndex(tail, -1, length - 1, v[i])] = v[i];
}
return length;
}
int main()
{
std::vector<int> v{ 1,2,2,3,4};
std::cout << "Length of Longest Increasing Subsequence is "
<< LongestIncreasingSubsequenceLength(v) << '\n';
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgoKLy8gQmluYXJ5IHNlYXJjaCAobm90ZSBib3VuZGFyaWVzIGluIHRoZSBjYWxsZXIpCmludCBDZWlsSW5kZXgoc3RkOjp2ZWN0b3I8aW50PiYgdiwgaW50IGwsIGludCByLCBpbnQga2V5KQp7Cgl3aGlsZSAociAtIGwgPiAxKSB7CgkJaW50IG0gPSBsICsgKHIgLSBsKSAvIDI7CgkJaWYgKHZbbV0gPj0ga2V5KQoJCQlyID0gbTsKCQllbHNlCgkJCWwgPSBtOwoJfQoKCXJldHVybiByOwp9CgppbnQgTG9uZ2VzdEluY3JlYXNpbmdTdWJzZXF1ZW5jZUxlbmd0aChzdGQ6OnZlY3RvcjxpbnQ+JiB2KQp7CglpZiAodi5zaXplKCkgPT0gMCkKCQlyZXR1cm4gMDsKCglzdGQ6OnZlY3RvcjxpbnQ+IHRhaWwodi5zaXplKCksIDApOwoJaW50IGxlbmd0aCA9IDE7IC8vIGFsd2F5cyBwb2ludHMgZW1wdHkgc2xvdCBpbiB0YWlsCgoJdGFpbFswXSA9IHZbMF07Cglmb3IgKHNpemVfdCBpID0gMTsgaSA8IHYuc2l6ZSgpOyBpKyspIHsKCgkJLy8gbmV3IHNtYWxsZXN0IHZhbHVlCgkJaWYgKHZbaV0gPCB0YWlsWzBdKQoJCQl0YWlsWzBdID0gdltpXTsKCgkJLy8gdltpXSBleHRlbmRzIGxhcmdlc3Qgc3Vic2VxdWVuY2UKCQllbHNlIGlmICh2W2ldID4gdGFpbFtsZW5ndGggLSAxXSkKCQkJdGFpbFtsZW5ndGgrK10gPSB2W2ldOwoKCQkvLyB2W2ldIHdpbGwgYmVjb21lIGVuZCBjYW5kaWRhdGUgb2YgYW4gZXhpc3RpbmcKCQkvLyBzdWJzZXF1ZW5jZSBvciBUaHJvdyBhd2F5IGxhcmdlciBlbGVtZW50cyBpbiBhbGwKCQkvLyBMSVMsIHRvIG1ha2Ugcm9vbSBmb3IgdXBjb21pbmcgZ3JlYXRlciBlbGVtZW50cwoJCS8vIHRoYW4gdltpXSAoYW5kIGFsc28sIHZbaV0gd291bGQgaGF2ZSBhbHJlYWR5CgkJLy8gYXBwZWFyZWQgaW4gb25lIG9mIExJUywgaWRlbnRpZnkgdGhlIGxvY2F0aW9uCgkJLy8gYW5kIHJlcGxhY2UgaXQpCgkJZWxzZQoJCQl0YWlsW0NlaWxJbmRleCh0YWlsLCAtMSwgbGVuZ3RoIC0gMSwgdltpXSldID0gdltpXTsKCX0KCglyZXR1cm4gbGVuZ3RoOwp9CgppbnQgbWFpbigpCnsKCXN0ZDo6dmVjdG9yPGludD4gdnsgMSwyLDIsMyw0fTsKCXN0ZDo6Y291dCA8PCAiTGVuZ3RoIG9mIExvbmdlc3QgSW5jcmVhc2luZyBTdWJzZXF1ZW5jZSBpcyAiCgkJCTw8IExvbmdlc3RJbmNyZWFzaW5nU3Vic2VxdWVuY2VMZW5ndGgodikgPDwgJ1xuJzsKCXJldHVybiAwOwp9Cg==