3467. 【NOIP2013模拟联考7】最长上升子序列(lis)

Description

维护一个序列,使它可以进行下面两种操作:

1.在末尾添加一个数字x

2.将整个序列变成第x次操作后的样子

在每次操作后,输出当前序列的最长上升子序列的长度

序列初始时为空

Input

输入文件lis.in的第一行有一个正整数n,表示操作个数。接下来n行每行有两个整数op,x。如果op为0,则表示添加x这个数字;如果op为1,则表示回到第x次操作之后。

Output

对于每次操作,在输出文件lis.out中输出一个答案,表示当前最长上升子序列的长度

Sample Input

5

0 2

0 0

1 0

1 0

0 5

Sample Output

1

1

0

0

1

【样例说明】

第一次操作后,序列为 2

第二次操作后,序列为2 0

第三次操作后,序列为(空)

第四次操作后,序列为(空)

第五次操作后,序列为 5

Data Constraint

30%的数据 n<=1000

另外20%的数据没有第二个操作

80%的数据 n<=200000

100%的数据 n<=500000且所有输入的数字都是长整型范围内的非负整数
想法:
这题前50分能水80分
f[i]表示最长上升子序列为i,第i位最小是多少
其实我们可以把所有操作变成一棵树,0操作就i-1与i连边,1操作x与i连边
然后从0开始遍历一棵树,1操作就什么都不变,0操作就改变f[],并把相应的改变记录
n太大卡dfs,猥琐的人工栈

Code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxN=500010;
int n,i,a[maxN],b[maxN],x,y,z,
tot,next[maxN],last[maxN],tov[maxN],
f[maxN],tail,ans[maxN],l,r,mid;
void insert(int x,int y){
    tov[++tot]=y,next[tot]=last[x],last[x]=tot;
}
struct zhj{
    int x,z,ch,wz,qz;
};
zhj pre[maxN];
int main(){
    freopen("lis.in","r",stdin);
    freopen("lis.out","w",stdout);
    scanf("%d",&n);
    for (i=1;i<=n;i++){
        scanf("%d%d",&a[i],&b[i]);
        if (a[i]==0) 
            insert(i-1,i);
        else insert(b[i],i);
    }
    ans[0]=0;
    tot=0;
    tail=1;
    pre[1].x=0;
    pre[1].z=last[0];
    while (tail>0){
        i=pre[tail].z;
        y=tov[i];
        if (y==19)
        {
            i=1;
        }
        if (a[y]==0){
            if (f[tot]<b[y]){
                f[++tot]=b[y];
                ans[y]=tot;
                pre[++tail].x=y;
                pre[tail].z=last[y];
                pre[tail].ch=1;
            }   
            else{
                l=1;r=tot;
                while (l<r){
                    mid=(l+r)/2;
                    if (f[mid]>=b[y]) r=mid;else l=mid+1;
                }
                z=f[l];
                f[l]=b[y];
                ans[y]=tot;
                pre[++tail].x=y;
                pre[tail].z=last[y];
                pre[tail].ch=0;
                pre[tail].wz=l;
                pre[tail].qz=z;
            }
        }
        else{
            ans[y]=tot;
            pre[++tail].x=y;
            pre[tail].z=last[y];
            pre[tail].ch=2; 
        }
        while ((pre[tail].z==0)&&(tail>=0)){
            if (pre[tail].ch==1)
                f[tot]=0,tot--;
            if (pre[tail].ch==0)
                f[pre[tail].wz]=pre[tail].qz;
            tail--;
            pre[tail].z=next[pre[tail].z];
        }
    }
    for (i=1;i<=n;i++)
        printf("%d\n",ans[i]);
}
发布了151 篇原创文章 · 获赞 71 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章