BZOJ3173 [Tjoi2013]最长上升子序列
Description
将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)求每一次插入的LIS
题解
每一次插入的数是递增的,所以我们知道对于一个数x,再最终数列的位置为
Dx
,
那么
f[Dx]=max(f[Dx],f[Dx−1])
为什么可以直接从最终序列来计算呢?
因为每次插入的X比已经插入的序列任意一个数都大,所以
对于X右边的数,肯定无影响。
对于X左边的数,影响的就是以X结尾的最终序列的LIS。
所以每次加入一个数,会产生一个在最终序列中以其结尾的LIS。
我们就要判断这个新产生的序列是否比加这个数之前的所有LIS长,类似于前缀的
方法统计每插入一个数得到的LIS。
所以关键是怎么求出这个最终序列,正解是用平衡树来求。然而数据比较水(其实是我不会treap),用vector可以水过。(笑~)
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#define MAXN 1000000+10
using namespace std;
int n,a[MAXN],f[MAXN],ans[MAXN],top=1;
int s[MAXN],d[MAXN];
vector<int> v;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
v.insert(v.begin()+x,i);
}
for(int i=1;i<=n;i++) d[v[i-1]]=i,a[i]=v[i-1];
top=1;s[top]=a[1];f[1]=1;
for(int i=2;i<=n;i++)
{
if(a[i]>s[top]) s[++top]=a[i],f[i]=top;
else
{
int k=lower_bound(s+1,s+top+1,a[i])-s;
s[k]=a[i],f[i]=k;
}
}
for(int i=1;i<=n;i++)
{
f[d[i]]=max(f[d[i]],f[d[i-1]]);
printf("%d\n",f[d[i]]);
}
return 0;
}