P4309 [TJOI2013] 最长上升子序列
P4309 [TJOI2013] 最长上升子序列
题目描述
给定一个序列,初始为空。现在我们将
数据范围:
说句闲话
应该没有那个神人想在线维护这玩意吧,毕竟两颗平衡树什么的还是太不可爱了。
solution:
我们先把所有操作离线然后用平衡树维护出最终的序列,再将每个数字所在位置映射到一个数组
然后我们思考一下以前我们怎么
维护一个数组,表示当前的 LIS 序列,然后二分一下当前点可以作为 LIS 上的哪个点然后优化一下。
但是我们发现对于本题,如果再用平衡树去维护这个东西貌似不太好写 (反正我debug写炸了,换了线段树)。
但是我们发现使用线段树也同样可以做到
我们开一颗线段树,维护一下以某个数为结尾的 LIS 的长度最大值
然后这题就做完了。
Code:
#include<bits/stdc++.h> const int N=1e5+5; const int inf=1e9; using namespace std; int rd(){return rand()*rand()+17;} struct FHQ_Treap{ int rt,cnt; int fa[N]; struct Tree{ int ls,rs,val,siz,pri; }t[N]; int Node(int val){t[++cnt]={0,0,val,1,rd()};return cnt;} void pushup(int x) { t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1; if(t[x].ls)fa[t[x].ls]=x; if(t[x].rs)fa[t[x].rs]=x; } void splite_siz(int x,int &a,int &b,int k) { if(!x){a=b=0;return ;}int tmp=t[t[x].ls].siz+1; if(k>=tmp){a=x;splite_siz(t[x].rs,t[x].rs,b,k-tmp);} else {b=x;splite_siz(t[x].ls,a,t[x].ls,k);} pushup(x); } int merge(int x,int y) { if(!x||!y)return x|y; if(t[x].pri<t[y].pri){t[x].rs=merge(t[x].rs,y);pushup(x);return x;} else {t[y].ls=merge(x,t[y].ls);pushup(y);return y;} } int get_siz(int x) { if(!x)return 0; int res=t[t[x].ls].siz+1; while(fa[x]) { if(t[fa[x]].rs==x)res+=t[t[fa[x]].ls].siz+1; x=fa[x]; } return res; } }T1; int n,ans; int a[N]; inline int Max(int x,int y){return x>y ? x : y;} struct Segment_Tree{ #define ls x<<1 #define rs x<<1|1 struct Tree{ int val; }t[N<<2]; inline void pushup(int x){t[x].val=Max(t[ls].val,t[rs].val);} void upd(int x,int l,int r,int pos,int k) { if(l==r){t[x].val=Max(t[x].val,k);return;} int mid=l+r>>1; if(pos<=mid)upd(ls,l,mid,pos,k); else upd(rs,mid+1,r,pos,k); pushup(x); } int query(int x,int l,int r,int L,int R) { if(R<l||r<L)return 0; if(L<=l&&r<=R){return t[x].val;} int mid=l+r>>1,res=0; if(L<=mid)res=Max(res,query(ls,l,mid,L,R)); if(mid<R) res=Max(res,query(rs,mid+1,r,L,R)); return res; } }T; void work() { cin>>n; for(int i=1,pos,a,b,c;i<=n;i++) { scanf("%d",&pos); T1.splite_siz(T1.rt,a,b,pos); T1.rt=T1.merge(T1.merge(a,T1.Node(i)),b); } for(int i=1;i<=n;i++) { a[i]=T1.get_siz(i); } for(int i=1;i<=n;i++) { int tmp=T.query(1,1,n,1,a[i])+1; ans=Max(ans,tmp); T.upd(1,1,n,a[i],tmp); printf("%d\n",ans); } } int main() { //freopen("P4309.in","r",stdin); freopen("P4309.out","w",stdout); work(); return 0; }