Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
Output
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
Sample Input
3
0 0 2
Sample Output
1
1
2
HINT
100%的数据 n<=100000
题解
在无数次wa后我终于发现我又理解错题意了。。
“表示我们将k插入到位置Xk”,这句话应该这样理解。。
假如原数列中第Xk个位置没有人,则插入至第Xk个,否则插入到第Xk个的前面,而不是替代Xk
拿样例说话,首先全部++
第一次插入 结果1
第二次插入 结果21
第三次插入 结果213…
而不是23
那。。从后往前,二分出每个数应该属于的位置。之后Nlogn的最长上升子序列即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int s[110000],n;
int lowbit(int x){return x&-x;}
void change_max(int x,int w){while(x<=n)s[x]=max(s[x],w),x+=lowbit(x);}
void change_sum(int x){while(x<=n)s[x]++,x+=lowbit(x);}
int findmax(int x)
{
int ret=0;
while(x>=1)ret=max(ret,s[x]),x-=lowbit(x);
return ret;
}
int findsum(int x)
{
int ret=0;
while(x>=1)ret+=s[x],x-=lowbit(x);
return ret;
}
int a[110000];
int main()
{
int maxx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i]++;}
for(int i=n;i>=1;i--)
{
int l=1,r=n;
while(l<r)
{
int mid=(l+r)/2;
int tmp=mid-findsum(mid);
if(tmp<a[i])l=mid+1;
else r=mid;
}
a[i]=l;change_sum(a[i]);
}
memset(s,0,sizeof(s));
int ans=0;
for(int i=1;i<=n;i++)
{
int tmp=findmax(a[i])+1;
change_max(a[i],tmp);
ans=max(ans,tmp);
printf("%d\n",ans);
}
return 0;
}