標籤:logs set algo 結構 長度 eve 計算 alt 操作
連結:http://www.lydsy.com/JudgeOnline/problem.php?id=3173
題意:向序列中動態插入$1~n$排列元素,求出插入每個元素後最長上升子序列長度。
如Claris所言,面對這種資料結構,必有高論。如果只想著資料結構,我們可以通過平衡樹動態維護序列,同時使用樹狀數組計算最長上升子序列。
但是我們不是猩猩不是資料結構狂人,我們畢竟還是要本著能不上樹就不上樹能少用資料結構就少用的原則來設計演算法的。
重新考慮這個題目。本題沒有要求強制線上,於是我們把整個操作倒過來看,於是問題就變成了不停地刪去序列中某個元素後求出當前最長上升子序列長度。
然後,不要忘了一個重要條件:這個東西是從小到大插入的。
從小到大插入,意味著插入一個數之後最長上升子序列發生變化的唯一可能就是以這個數結尾。
那麼我們就維護一下刪掉每個數之前以這個數結尾的最長上升子序列就好了,最後輸出答案時,將這個與前一個比較,短就直接將當前這個數賦值成為上一個。
說得簡單……但是這道題真的是一個樹狀數組綜合運用……具體看代碼吧……
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int lowbit(int x) 7 { 8 return x&(-x); 9 }10 const int maxn=100005;11 int C[maxn],n;12 void Modify(int pos,int val)13 {14 for(;pos<=n;pos+=lowbit(pos))C[pos]+=val;15 }16 void Maximum(int pos,int val)17 {18 for(;pos<=n;pos+=lowbit(pos))C[pos]=max(C[pos],val);19 }20 int Query_kth(int k)21 {22 int cnt=0,ans=0;23 for(int i=17;~i;i--)24 {25 ans+=(1<<i);26 if(ans>=n||cnt+C[ans]>=k)ans-=(1<<i);27 else cnt+=C[ans];28 }29 return ans+1;30 }31 int Query_max(int pos)32 {33 int res=0;34 for(;pos;pos-=lowbit(pos))res=max(res,C[pos]);35 return res;36 }37 int a[maxn],b[maxn],f[maxn];38 int haha()39 {40 scanf("%d",&n);41 for(int i=1;i<=n;i++)42 {43 scanf("%d",&a[i]);C[i]++;44 if((i+lowbit(i))<=n)C[i+lowbit(i)]+=C[i];45 }46 int tmp;47 for(int i=n;i;i--)b[tmp=Query_kth(a[i]+1)]=i,Modify(tmp,-1);48 memset(C,0,sizeof(C));49 for(int i=1;i<=n;i++)f[b[i]]=Query_max(b[i])+1,Maximum(b[i],f[b[i]]);50 for(int i=1;i<=n;i++)printf("%d\n",f[i]<f[i-1]?(f[i]=f[i-1]):f[i]);51 }52 int sb=haha();53 int main(){;}bzoj3173
bzoj3173 最長上升子序列 樹狀數組