bzoj3173 最長上升子序列 樹狀數組

連接:http://www.lydsy.com/JudgeOnline/problem.php?id=3173php

題意:向序列中動態插入$1~n$排列元素,求出插入每一個元素後最長上升子序列長度。ios

如Claris所言,面對這種數據結構,必有高論。若是隻想着數據結構,咱們能夠經過平衡樹動態維護序列,同時使用樹狀數組計算最長上升子序列。算法

可是咱們不是猩猩不是數據結構狂人,咱們畢竟仍是要本着能不上樹就不上樹能少用數據結構就少用的原則來設計算法的。數組

從新考慮這個題目。本題沒有要求強制在線,因而咱們把整個操做倒過來看,因而問題就變成了不停地刪去序列中某個元素後求出當前最長上升子序列長度。數據結構

而後,不要忘了一個重要條件:這個東西是從小到大插入的。ide

從小到大插入,意味着插入一個數以後最長上升子序列發生變化的惟一可能就是以這個數結尾。spa

那麼咱們就維護一下刪掉每一個數以前以這個數結尾的最長上升子序列就行了,最後輸出答案時,將這個與前一個比較,短就直接將當前這個數賦值成爲上一個。設計

說得簡單……可是這道題真的是一個樹狀數組綜合運用……具體看代碼吧……code

 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
相關文章
相關標籤/搜索