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 }