1059 -- 最长上升子序列
Description
维护一个序列,使它可以进行下面两种操作:1.在末尾添加一个数字x
2.将整个序列变成第x次操作后的样子
在每次操作后,输出当前序列的最长上升子序列的长度
序列初始时为空
Input
第一行有一个正整数n,表示操作个数。接下来n行每行有两个整数op,x。如果op为0,则表示添加x这个数字;如果op为1,则表示回到第x次操作之后。
Output
对于每次操作,输出一个答案,表示当前最长上升子序列的长度。Sample Input
50 2
0 0
1 0
1 0
0 5
Sample Output
11
0
0
1
Hint
30%的数据: n≤1000;另外20%的数据没有第二个的操作
80%的数据: n≤200000;
100%的数据:n≤500000 ,且所有输入的数字都是长整型范围内的非负整数
Source
2014NOIP模拟题Hide Information »
题解:我觉得有点难啊啊啊啊DP题,LIS进阶版哦
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> typedef long long ll; using namespace std; const ll N=500002; const ll oo=10000000000000000; ll op[N],f[N],head[N]; ll a[N]; int ans[N]; struct node{ ll next; ll to; }e[N]; ll cnt,n; void add(ll u,ll v){ cnt++; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } void dfs(ll now){ if(op[now]==1){ ans[now]=lower_bound(f,f+1+n,oo)-(f+1); for(ll i=head[now];i;i=e[i].next) dfs(e[i].to); } if(op[now]==0){ ll ps=lower_bound(f,f+1+n,a[now])-f; ll tmp=f[ps]; f[ps]=a[now]; ans[now]=lower_bound(f,f+1+n,oo)-(f+1); for(ll i=head[now];i;i=e[i].next) dfs(e[i].to); f[ps]=tmp; } } int main(){ freopen("1059.in","r",stdin); freopen("1059.out","w",stdout); cin>>n; for(ll i=1;i<=n;i++){ cin>>op[i]>>a[i]; if(op[i]==1) add(a[i],i); else add(i-1,i); } op[0]=1; for(ll i=1;i<=n;i++) f[i]=oo; dfs(0); for(ll i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }