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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章