BZOJ3173 [Tjoi2013]最长上升子序列

来源:互联网 发布:项目 书籍 商务 知乎 编辑:程序博客网 时间:2024/06/07 02:24

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[Dx1])

为什么可以直接从最终序列来计算呢?
因为每次插入的X比已经插入的序列任意一个数都大,所以
对于X右边的数,肯定无影响。
对于X左边的数,影响的就是以X结尾的最终序列的LIS。
所以每次加入一个数,会产生一个在最终序列中以其结尾的LIS。
我们就要判断这个新产生的序列是否比加这个数之前的所有LIS长,类似于前缀的
方法统计每插入一个数得到的LIS。

所以关键是怎么求出这个最终序列,正解是用平衡树来求。然而数据比较水(其实是我不会treap),用vector可以水过。(笑~)

#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <vector>#define MAXN 1000000+10using 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;}
0 1