BZOJ3173: [Tjoi2013]最长上升子序列

1~n<=1e5依次插入序列中某一个位置,求每次插入后的最长上升子序列。

因为新插入的数对前面插入的答案没影响,所以只要能想方设法构造出最终序列即可。

方法一:平衡树!。。。。

方法二:在树状数组上倍增求第K大

然而LIS写残了。。记得是lowerbound不是upper。。

然后最后输出记得和前面小的答案取max因为新插入后最长上升子序列并不一定涉及新插入的数。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<math.h>
 6 //#include<queue>
 7 //#include<iostream>
 8 using namespace std;
 9 
10 int n;
11 #define maxn 100011
12 int a[maxn];
13 struct BIT
14 {
15     int a[maxn];
16     BIT() {memset(a,0,sizeof(a));}
17     void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;}
18     int find(int x)
19     {
20         int now=0,ans=0;
21         for (int i=19;i>=0;i--)
22         {
23             now+=(1<<i);
24             if (now>=n || ans+a[now]>=x) now-=(1<<i);
25             else ans+=a[now];
26         }
27         return now+1;
28     }
29 }t;
30 int num[maxn],g[maxn],last[maxn];
31 int main()
32 {
33     scanf("%d",&n);
34     for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]++,t.a[i]++,t.a[i+(i&-i)]+=t.a[i];
35     for (int i=n;i;i--)
36     {
37         int tmp=t.find(a[i]);
38         num[tmp]=i;
39         t.add(tmp,-1);
40     }
41     int ans=0;
42     for (int i=1;i<=n;i++)
43     {
44         int now=lower_bound(g,g+ans+1,num[i])-g;
45         if (now<=ans) g[now]=min(g[now],num[i]);
46         else ans++,g[ans]=num[i];
47         last[num[i]]=now;
48     }
49     for (int i=1;i<=n;i++) last[i]=max(last[i-1],last[i]),printf("%d\n",last[i]);
50     return 0;
51 }
View Code

 

posted @ 2017-10-20 07:13  Blue233333  阅读(326)  评论(0编辑  收藏  举报