方法一: 二分
我们可以知道 最长上升子序列的 最后一个数的值是随序列的长度而递增的 (呃呃呃 意会意会)
然后我们就可以二分找值了(并更新)
//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,cases,a[100050],f[100050],vis[100050];
int search(int x){int l=0,r=n,ans=0;while(l<=r){int mid=(l+r)>>1;if(vis[mid]<=x)l=mid+1,ans=mid;else r=mid-1;}return ans;
}
int main()
{scanf("%d",&cases);while(cases--){memset(f,0,sizeof(f));memset(vis,0x3f,sizeof(vis)),vis[0]=0;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++){f[i]=search(a[i])+1;vis[f[i]]=min(vis[f[i]],a[i]);}for(int i=1;i<n;i++)f[n]=max(f[n],f[i]);printf("%d\n",f[n]);}
}
方法二:
线段树 (按照权值建) 查询前一段中的最大值。。并插入当前的值,,
//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,cases,a[100050],f[100050],xx,tree[666666];
void insert(int l,int r,int pos){if(l==r){tree[pos]=f[xx];return;}int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;if(mid<a[xx])insert(mid+1,r,rson);else insert(l,mid,lson);tree[pos]=max(tree[lson],tree[rson]);
}
int query(int l,int r,int pos){if(r<=a[xx])return tree[pos];int mid=(l+r)>>1;if(mid<a[xx])return max(query(l,mid,pos<<1),query(mid+1,r,pos<<1|1));else return query(l,mid,pos<<1);
}
int main(){scanf("%d",&cases);while(cases--){memset(tree,0,sizeof(tree));memset(f,0,sizeof(f));scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(xx=1;xx<=n;xx++){f[xx]=query(1,n,1)+1;insert(1,n,1);}for(int i=1;i<n;i++)f[n]=max(f[n],f[i]);printf("%d\n",f[n]);}
}