Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
Output
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
因为后面插入的数一定比前面的大, 所以更后插入的对当前的答案没有任何影响,所以预处理出每个数的最终位置,然后动态规划即可。
时间复杂度O(nlogn)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string> 4 #include<string.h> 5 #include<iostream> 6 #include<algorithm> 7 #include<queue> 8 #include<math.h> 9 #include<vector> 10 #include<map> 11 #include<set> 12 #define il inline 13 #define re register 14 using namespace std; 15 const int N=1000001; 16 int l[N],r[N],rnd[N],siz[N],v[N],s[N],cnt,now,root,n,ans[N],g; 17 il void update(re int k){ 18 siz[k]=siz[l[k]]+siz[r[k]]+1; 19 } 20 il void rturn(re int &k){ 21 int t=l[k];l[k]=r[t];r[t]=k;update(k);update(t);k=t; 22 } 23 il void lturn(re int &k){ 24 int t=r[k];r[k]=l[t];l[t]=k;update(k);update(t);k=t; 25 } 26 il void insert(re int &k,re int rank){ 27 if(!k){ 28 k=(++cnt);rnd[k]=rand();siz[k]=1;return; 29 } 30 siz[k]++; 31 if(siz[l[k]]<rank){ 32 insert(r[k],rank-siz[l[k]]-1); 33 if(rnd[r[k]]<rnd[k]) lturn(k); 34 } 35 else{ 36 insert(l[k],rank); 37 if(rnd[l[k]]<rnd[k]) rturn(k); 38 } 39 } 40 il int read(){ 41 re int hs=0;re char c=getchar(); 42 while(!isdigit(c)) c=getchar(); 43 while(isdigit(c)){ 44 hs=(hs<<3)+(hs<<1)+c-‘0‘; 45 c=getchar(); 46 } 47 return hs; 48 } 49 il void dfs(re int k){ 50 if(!k) return; 51 dfs(l[k]); 52 v[++now]=k; 53 dfs(r[k]); 54 } 55 int main(){ 56 memset(s,127,sizeof(s));s[0]=-1000000000;n=read(); 57 for(re int i=1,x;i<=n;i++){ 58 x=read();insert(root,x); 59 } 60 dfs(root); 61 for(re int i=1,t;i<=n;i++){ 62 t=upper_bound(s,s+g+1,v[i])-s; 63 if(s[t-1]<=v[i]){ 64 s[t]=min(s[t],v[i]); 65 ans[v[i]]=t; 66 g=max(g,t); 67 } 68 } 69 for(re int i=1;i<=n;i++){ 70 ans[i]=max(ans[i-1],ans[i]); 71 printf("%d\n",ans[i]); 72 } 73 return 0; 74 }
时间: 2024-10-13 21:03:10