D - LIS 2 Editorial by evima
For a sequence \(X = (x_1,\ldots,x_N)\) with around \(2 \times 10^5\) elements, we can find the LIS as follows (the settings are slightly modified from usual to be used in the following solution).
- For \(1 \leq i \leq N\), let \(\mathrm{dp}_i\) be the smallest value of the last element of a length-\(i\) strictly increasing subsequence.
- For \(i=1,2,\ldots,N\) in this order, find the smallest \(j\) such that \(\mathrm{dp_j} \geq x_i\) with binary search, and update \(\mathrm{dp_j}\) to \(x_i\).
- The answer is the number of indices \(i\) such that \(\mathrm{dp_i} \neq \mathrm{Inf}\) in the end.
Let us apply this to our problem. Consider a length-\(10^9\) binary sequence whose \(x\)-th element is \(1\) if there is \(i\) such that \(\mathrm{dp}_i =x \) and \(0\) otherwise. Then, for \((l_i,r_i)\), we need to change to \(0\) at most \((r_i-l_i+1)\) \(1\)s from the left whose indices are at least \(l_i\), and change to \(1\) the \(l_i\)-th through \(r_i\)-th elements. One can simulate this process in \(\mathrm{O}(N \log N)\) time in total by compressing the indices and then using a lazy segment tree that supports ranged update and addition.
Alternatively, one can use map to maintain segments in the array \(\mathrm{dp}\) whose values increase by \(1\) from left to right like \(5,6,7,\ldots\) to find the answer fast enough.
Sample Implementation (C++)
#include <bits/stdc++.h>
#include <atcoder/lazysegtree>
using namespace atcoder;
using namespace std;
pair<int,int> op(pair<int,int> a,pair<int,int> b){
a.first += b.first;
a.second += b.second;
return a;
}
pair<int,int> e(){
return make_pair(0,0);
}
pair<int,int> mapping(int a,pair<int,int> b){
if(a==-1)return b;
b.first = b.second * a;
return b;
}
int composition(int a,int b){
if(a==-1)return b;
return a;
}
int id(){
return -1;
}
int X;
bool f(pair<int,int> x){
return x.first<=X;
}
int main() {
int N;
cin>>N;
vector<int> l(N),r(N);
vector<int> t;
for(int i=0;i<N;i++){
cin>>l[i]>>r[i];
r[i]++;
t.push_back(l[i]);
t.push_back(r[i]);
}
sort(t.begin(),t.end());
t.erase(unique(t.begin(),t.end()),t.end());
vector<pair<int,int>> temp;
for(int i=0;i<t.size()-1;i++){
temp.emplace_back(0,t[i+1]-t[i]);
}
lazy_segtree<pair<int,int>,op,e,int,mapping,composition,id> seg(temp);
for(int i=0;i<N;i++){
int il = distance(t.begin(),lower_bound(t.begin(),t.end(),l[i]));
int ir = distance(t.begin(),lower_bound(t.begin(),t.end(),r[i]));
X = r[i]-l[i];
int rr = seg.max_right<f>(il);
X -= seg.prod(il,rr).first;
seg.apply(il,rr,0);
if(rr!=temp.size()){
auto g = seg.get(rr);
g.first -= X;
seg.set(rr,g);
}
seg.apply(il,ir,1);
}
cout<<seg.all_prod().first<<endl;
return 0;
}
posted:
last update: