BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]
3173: [Tjoi2013]最长上升子序列
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1613 Solved: 839
[Submit][Status][Discuss]
Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
Input
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
Output
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
Sample Input
3
0 0 2
0 0 2
Sample Output
1
1
2
1
2
HINT
100%的数据 n<=100000
插入的数字是递增的,也就是说插入数字后不会改变其他元素的dp值
有一个离线做法:用treap动态把序列弄出来然后求lis
http://hzwer.com/6254.html
在线用splay,f表示以当前元素结尾的LIS长度,mx表示他的子树里最大的f
把新插入的元素转到根后,f就是左子树mx+1(不可能有非法的因为递增啊)
注意:
1.别忘哨兵
2.别忘更新size时还要+1
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; #define lc t[x].ch[0] #define rc t[x].ch[1] #define pa t[x].fa const int N=1e5+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n,k; struct node{ int ch[2],fa,size,v,f,mx; node():fa(0){ch[0]=ch[1]=0;} }t[N]; int sz,root; inline int wh(int x){return t[pa].ch[1]==x;} inline void update(int x){ t[x].size=t[lc].size+t[rc].size+1; t[x].mx=max(t[x].f,max(t[lc].mx,t[rc].mx)); } inline void rotate(int x){ int f=t[x].fa,g=t[f].fa,c=wh(x); if(g) t[g].ch[wh(f)]=x;t[x].fa=g; t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f; t[x].ch[c^1]=f;t[f].fa=x; update(f);update(x); } inline void splay(int x,int tar){ for(;t[x].fa!=tar;rotate(x)) if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x); if(tar==0) root=x; } inline int kth(int k){ int x=root,lsize=0; while(x){ int _=lsize+t[lc].size; if(_<k&&k<=_+1) return x; else if(k<=_) x=lc; else lsize=_+1,x=rc; } return 0; } inline int nw(int v){ sz++;t[sz].v=v;t[sz].size=1; return sz; } inline void Sol(int k,int v){//printf("Sol %d %d\n",k,v); int f=kth(k+1);splay(f,0);//puts("hi"); int x=kth(k+2);splay(x,f);//printf("ran %d %d\n",f,x); lc=nw(v);t[lc].fa=x; update(x);update(f); splay(sz,0); t[sz].f=t[t[sz].ch[0]].mx+1;update(sz); //printf("f %d %d %d\n",sz,t[sz].ch[0],t[sz].f); printf("%d\n",t[sz].mx); } int main(){ //freopen("in.txt","r",stdin); n=read(); root=nw(0);t[root].ch[1]=nw(N);t[sz].fa=root; for(int i=1;i<=n;i++){ k=read(); Sol(k,i); } }
Copyright:http://www.cnblogs.com/candy99/