[Tjoi2013]最长上升子序列
Submit: 2294 Solved: 1153
[Submit][Status][Discuss]
Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
Output
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
Sample Input
3
0 0 2
0 0 2
Sample Output
1
1
2
1
2
HINT
100%的数据 n<=100000
首先先不管答案,先看看怎么维护序列。
然后发现这就是一个裸的splay/treap,找到第k大然后旋到根然后把当前点查到后继的左儿子就ojbk了。
所以怎么回答询问呢???
我们设ans[i]为在最终序列里的以i结尾的最长上升子序列长度,那么第i次询问的答案就是max(ans[1],ans[2],,,,ans[i])。
为什么呢?
因为后加入的肯定都比前i个数大,所以不会对答案产生影响,所以最终序列以前i个数结尾的LIS就是第i次询问的答案。
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; int root,ch[maxn][2]; int f[maxn],siz[maxn],pos; int n,m,ans[maxn],g[maxn]; int b[maxn],cnt,tot; inline int get(int x){ return ch[f[x]][1]==x; } inline void update(int x){ siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]]; } inline void rotate(int x){ int fa=f[x],ffa=f[fa],tp=get(x); ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa; ch[x][tp^1]=fa,f[fa]=x; f[x]=ffa; if(fa==root) root=x; if(ffa) ch[ffa][ch[ffa][1]==fa]=x; update(fa),update(x); } inline void splay(int x){ for(int fa;(fa=f[x]);rotate(x)) if(f[fa]) rotate(get(fa)==get(x)?fa:x); } inline void kth(int k){ int now=root; while(1){ if(k<=siz[ch[now][0]]) now=ch[now][0]; else{ k-=siz[ch[now][0]]+1; if(k<=0){ splay(now); return; } now=ch[now][1]; } } } inline void insert_front(){ if(!root){ root=++cnt; siz[cnt]=1; return; } int now=root,fa; while(now){ siz[now]++; fa=now,now=ch[now][0]; } siz[++cnt]=1,f[cnt]=fa,ch[fa][0]=cnt; update(fa); } inline void insert_back(){ if(!ch[root][1]){ ch[root][1]=++cnt; siz[cnt]=1,f[cnt]=root; update(root); return; } siz[root]++; int now=ch[root][1]; while(ch[now][0]) siz[now]++,now=ch[now][0]; siz[now]++; ch[now][0]=++cnt,siz[cnt]=1,f[cnt]=now; } inline void updata(int x,int y){ for(;x<=n;x+=x&-x) g[x]=max(g[x],y); } inline int query(int x){ int mx=0; for(;x;x-=x&-x) mx=max(mx,g[x]); return mx; } inline void build(int x){ if(ch[x][0]) build(ch[x][0]); b[++tot]=x; if(ch[x][1]) build(ch[x][1]); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&pos); if(!pos) insert_front(); else{ kth(pos); insert_back(); } } build(root); for(int i=1;i<=n;i++){ int now=query(b[i]-1)+1; ans[b[i]]=now; updata(b[i],now); } for(int i=1;i<=n;i++){ ans[i]=max(ans[i],ans[i-1]); printf("%d\n",ans[i]); } return 0; }
我爱学习,学习使我快乐