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; }
作者:凤涅
本文版权归作者所有,遵循CC-BY-4.0协议,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

浙公网安备 33010602011771号