1. 程式人生 > >【bzoj 3173】最長上升子序列

【bzoj 3173】最長上升子序列

傳送門~

解題思路

因為是1~n順序插入,所以新插入元素不會對之前已經求出的值產生影響。以新插入元素為結尾的最長上升子序列為它插入位置之前所有元素的maxx加1。用平衡樹維護,支援插入和查詢。
程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<string>
using namespace std;
struct
node{ int mx,yx,siz,key; node* ch[2]; }*root=NULL; int n,ans,rans,xk; void Rotate(node* &p,bool f){ node *t=p->ch[f^1]; p->ch[f^1]=t->ch[f]; t->ch[f]=p; p->siz=1;p->mx=p->key; if(p->ch[0]!=NULL) {p->siz+=p->ch[0]->siz;p->mx=max(p->mx,p->ch[0
]->mx);} if(p->ch[1]!=NULL) {p->siz+=p->ch[1]->siz;p->mx=max(p->mx,p->ch[1]->mx);} t->siz=1;t->mx=t->key; if(t->ch[0]!=NULL) {t->siz+=t->ch[0]->siz;t->mx=max(t->mx,t->ch[0]->mx);} if(t->ch[1]!=NULL) {t->siz+=t->ch[1]->siz;t->mx=max(t->mx,t->ch[1
]->mx);} p=t; } void ch(node* &p,int sum){ int s=0; if(p==NULL || sum==0) return ; if(p->ch[0]!=NULL) s+=p->ch[0]->siz; if(sum>s) { if(p->ch[0]!=NULL) rans=max(rans,p->ch[0]->mx); rans=max(rans,p->key); ch(p->ch[1],sum-s-1); } else if(sum<s) ch(p->ch[0],sum); else rans=max(rans,p->ch[0]->mx); } void Insert(node* &p,int sum){ if(p==NULL) { p=new node; p->mx=p->key=rans; p->siz=1;p->yx=rand(); return ; } int s=0; if(p->ch[0]!=NULL) s+=p->ch[0]->siz; if(sum<=s) { Insert(p->ch[0],sum); if(p->yx>p->ch[0]->yx) Rotate(p,1); else { p->siz++; p->mx=max(p->mx,p->ch[0]->mx); } } else { Insert(p->ch[1],sum-s-1); if(p->yx>p->ch[1]->yx) Rotate(p,0); else { p->siz++; p->mx=max(p->mx,p->ch[1]->mx); } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&xk); rans=0;ch(root,xk); rans++;ans=max(rans,ans); Insert(root,xk);printf("%d\n",ans); } return 0; }