https://www.lydsy.com/JudgeOnline/problem.php?id=3173php
插入的数是以递增的顺序插入的ios
这说明若是倒过来考虑,那么从最后一个插入的开始删除,不会对以某个数结尾的最长上升子序列产生影响git
因此 先原序列求出来,输出便可数组
还原原序列的方法:spa
能够用平衡树,dfs序就是原序列code
嫌麻烦,不想写,因此 树状数组blog
假设最后一个数是n,插入位置是y,get
倒数第二个数是n-1,插入位置是xit
那么y就是n的最终位置io
若是y在x后面,那么x就是n-1的最终位置
若是y在x前面,那么x+1就是n-1的最终位置
因此 若是倒序插入每一个数,
若数m的插入位置为p,
数m的最终位置就是当前序列 的 第p个空位
这能够二分+树状数组肯定 数m的位置
注意求LIS时,求出的f[i] 时 以i结尾的LIS
要求回答 序列的LIS,因此要跟f[i-1]取大
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 #define lowbit(x) x&-x int n; int p[N]; int c[N]; int a[N]; int dp[N],m; int f[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int pos,int x) { while(pos<=n) { c[pos]+=x; pos+=lowbit(pos); } } int query(int x) { int sum=0; while(x) { sum+=c[x]; x-=lowbit(x); } return sum; } int find(int x) { int l=1,r=n,mid,tmp; while(l<=r) { mid=l+r>>1; if(mid-query(mid)>=x) tmp=mid,r=mid-1; else l=mid+1; } return tmp; } void init() { read(n); for(int i=1;i<=n;++i) read(p[i]); int pos; for(int i=n;i;--i) { pos=find(p[i]+1); a[pos]=i; add(pos,1); } } void pre_LIS() { dp[m=1]=a[1]; f[a[1]]=1; int pos; for(int i=2;i<=n;++i) { if(a[i]>dp[m]) { dp[++m]=a[i]; f[a[i]]=m; } else { pos=lower_bound(dp+1,dp+m+1,a[i])-dp; if(a[i]<dp[pos]) dp[pos]=a[i]; f[a[i]]=pos; } } } void solve() { int now=0; for(int i=1;i<=n;++i) { now=max(now,f[i]); printf("%d\n",now); } } int main() { init(); pre_LIS(); solve(); }