lis-Intuidiff II

题意大概为求时间段的最长上升子序列。但本萌新只会n^2的解法,只能无奈地tle。于是比赛完就找wcy要了一份nlogn的解法,学习一下。

nlogn的解法基于这样一个思路:储存长度为i的lis的最小末尾j,下记作d i=j。容易看出,我们不需要那些长度为i但末尾更大的值,而且d是单调递增的。

而d的维护思路如下:设当前最长长度为len,如果a i大于d len,那显然它可以组成一个len+1长度的子序列,遂更新d len+1=a i。否则,找到 j 使得d j<a i<=d j+1,然后d j+1就可以从d j加上a i转移到d j+1,遂更新d j+1,这一步可以二分实现,或者用lower_bound()。所以总复杂度就是nlogn。

代码如下:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    map<int,int>m;
    m[-1]=0;
    for(int i=0;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        auto it=m.lower_bound(a);
        it--;
        int ans=it->second+b-a+1;
        //cout<<"ans="<<ans<<endl;
        if(m.count(b)){
            if(m[b]<ans)
                m[b]=ans;
        }
        else{
            auto inew=m.lower_bound(b);
            inew--;
            //cout<<"**"<<inew->second<<endl;
            if(inew->second<ans)
                m[b]=it->second+b-a+1;
        }
    //cout<<'*'<<m.size()<<endl;
        auto inew1=m.upper_bound(b);
        auto inew2=inew1;
        while(inew2!=m.end()&&inew2->second<=ans)
            inew2++;
        m.erase(inew1,inew2);
    }
    auto i=m.end();
    i--;
    cout<<i->second<<endl;
    return 0;
}

 

posted @ 2019-06-07 16:46  wengsy150943  阅读(217)  评论(0)    收藏  举报