给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
标签:limit enter page tmp href 插入 lin roo 序列
100%的数据 n<=100000
有一个离线做法:用treap动态把序列弄出来然后求lis
http://hzwer.com/6254.html
在线用splay
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 100003 using namespace std; int n,root; int key[N],size[N],ch[N][3],fa[N],sz,maxn[N],g[N]; int get(int x) { return ch[fa[x]][1]==x; } void update(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; maxn[x]=g[x]; maxn[x]=max(maxn[x],maxn[ch[x][0]]); maxn[x]=max(maxn[x],maxn[ch[x][1]]); if (key[x]==1000000000||key[x]==0) maxn[x]=0,g[x]=0; } void rotate(int x) { int y=fa[x]; int z=fa[y]; int which=get(x); if (z) ch[z][ch[z][1]==y]=x; fa[x]=z; ch[y][which]=ch[x][which^1]; fa[ch[y][which]]=y; ch[x][which^1]=y; fa[y]=x; update(y); update(x); } void splay(int x,int tar) { for (int f;(f=fa[x])!=tar;rotate(x)) if (fa[f]!=tar) rotate(get(x)==get(f)?f:x); if (!tar) root=x; } int find(int x) { int now=root; while (true) { if (x<=size[ch[now][0]]) now=ch[now][0]; else { int tmp=size[ch[now][0]]+1; if (tmp==x) return now; x-=tmp; now=ch[now][1]; } } } int main() { scanf("%d",&n); root=++sz; key[sz]=1000000000; size[root]=2; fa[root]=0; ch[root][1]=++sz; key[sz]=0; size[sz]=1; ch[sz][1]=ch[sz][0]=0; fa[sz]=root; for (int i=1;i<=n;i++) { int x; scanf("%d",&x); x++; int aa=find(x); int bb=find(x+1); splay(aa,0); splay(bb,aa); int t=ch[root][1]; ch[t][0]=++sz; fa[sz]=t; key[sz]=i; ch[sz][1]=ch[sz][0]=0; size[sz]=1; splay(t,0); splay(sz,0); g[sz]=maxn[ch[root][0]]+1; update(sz); printf("%d\n",maxn[sz]); } }
BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]
标签:limit enter page tmp href 插入 lin roo 序列
原文地址:http://www.cnblogs.com/candy99/p/6286176.html