標籤:
題意:連結方法: Treap+LIS解析:剛看到題還蒙了一會,無從下手啊- -!後來尋思找找規律。畫畫範例以及瞎編了兩組資料之後發現點問題…答案遞增?然後才反應過來- -,當我們從小到大插入的時候,插入後的情況是不影響插入前的。所以這樣的話我們可以把整個序列先弄出來?之後求一個LIS,這時候對於每一個數來說,他都有個LIS值,當然這個可能不是他插入之後的最優解,因為之前的值可能比他插入之後還要大。所以我們再需要掃一下數組,更新下答案即可。至於第一部分找序列,用treap實現是很優越的。第二部分呢?n^2的做法顯然這裡是過不了的,所以nlogn就好。大複雜度O(nlogn)代碼:
#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#define N 100010using namespace std;int size,n,root;struct node{ int l,r,rnd,siz,w,v;}tr[N];void pushup(int rt){ tr[rt].siz=tr[tr[rt].l].siz+tr[tr[rt].r].siz+1; }void lturn(int &rt){ int t=tr[rt].r; tr[rt].r=tr[t].l; tr[t].l=rt; tr[t].siz=tr[rt].siz; pushup(rt); rt=t;}void rturn(int &rt){ int t=tr[rt].l; tr[rt].l=tr[t].r; tr[t].r=rt; tr[t].siz=tr[rt].siz; pushup(rt); rt=t;}void insert(int &rt,int v){ if(!rt) { rt=++size; tr[rt].l=tr[rt].r=0,tr[rt].siz=1; tr[rt].v=size,tr[rt].rnd=rand(); return; } tr[rt].siz++; if(v<=tr[tr[rt].l].siz+1) { insert(tr[rt].l,v); if(tr[tr[rt].l].rnd<tr[rt].rnd)rturn(rt); }else { insert(tr[rt].r,v-tr[tr[rt].l].siz-1); if(tr[tr[rt].r].rnd<tr[rt].rnd)lturn(rt); }}int tot;int seq[N];void getseq(int rt){ if(tr[rt].l!=0) getseq(tr[rt].l); seq[++tot]=tr[rt].v; if(tr[rt].r!=0) getseq(tr[rt].r);}int f[N],d[N],ans[N];int print[N]; void getlis(){ memset(d,0x3f,sizeof(d)); d[0]=0; d[1]=seq[1],f[1]=1; int mx=1; for(int i=2;i<=n;i++) { if(seq[i]>d[mx]) { f[i]=++mx; d[mx]=min(d[mx],seq[i]); }else { int l=0,r=mx,ans=0; while(l<=r) { int mid=(l+r)>>1; if(d[mid]<seq[i])ans=mid,l=mid+1; else r=mid-1; } f[i]=ans+1; d[ans+1]=min(d[ans+1],seq[i]); } }}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { int x; scanf("%d",&x);x++; insert(root,x); } getseq(root); getlis(); for(int i=1;i<=n;i++)print[seq[i]]=f[i]; for(int i=1;i<=n;i++)print[i]=max(print[i],print[i-1]); for(int i=1;i<=n;i++)printf("%d\n",print[i]);}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
BZOJ 3173 [Tjoi2013]最長上升子序列 Treap+LIS