Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
Output
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
Solution
因为后插进去的优先级更高,考虑倒序解决这个问题。
通过倒序插入确定了每一个点的真正位置。
不过需要注意后面已经插入的对前面的影响。
所以通过二分确定位置pos。
答案pos=后面在位置pos前插的个数+这次操作插的位置x
然后按正常逆序对做就行了。
Code
#include<bits/stdc++.h>
using namespace std;
int a[210010],n;
int pos[210010];
int sum[210010];
int p[210010];
int lowbit(int x){
return x&-x;
}
void add(int pos,int x){
for(int i=pos;i<=n;i+=lowbit(i))
sum[i]=max(sum[i],x);
}
void add1(int x){
for(int i=x;i<=n;i+=lowbit(i))
pos[i]++;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans=max(ans,sum[i]);
return ans;
}
int query1(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=pos[i];
return ans;
}
int get(int x){
int l=x,r=n,ans=x;
while(l<=r){
int mid=(l+r)/2;
if(query1(mid)<=mid-x) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main(){
int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]++;
for(int i=n;i;i--){
p[i]=get(a[i]);
add1(p[i]);
}
for(int i=1;i<=n;i++){
int x=query(p[i]-1)+1;
add(p[i],x);
ans=max(ans,x);
printf("%d\n",ans);
}
}
/*
7
5
1
1
1
0
0
2
*/
博客讨论了如何解决一个关于最长上升子序列的问题,其中涉及在给定序列中按特定位置插入数字。每插入一个数字,需要找出当前最长上升子序列的长度。解决方案建议从后往前考虑,使用二分查找确定每个数字的正确位置,并更新最长上升子序列的长度。

1067

被折叠的 条评论
为什么被折叠?



