题意:
你有
n
n
n个数,每个数会插到一个位置,告诉你每个插到数列后的位置,问你每一个数插完之后的最长上升子序列长度。
n
<
=
1
e
5
n<=1e5
n<=1e5。
题解:
带插入的最长上升子序列,由于不是强制在线,于是我搞了个离线做法。
我的做法是先用一个平衡树来维护出插入后序列每个位置的数值,然后用一个nlogn的dp来算每个数插入后以某个这个位置的数为结尾的最长上升子序列。在查询的时候,我们倒着枚举。我们找到 i i i这个数字所在的位置,然后把dp值删去就好了。
现在脑子有点混乱,不太想多讲了。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,a[200010],f[200010],ch[200010][2],sz[200010],root,cnt,val[200010];
int b[200010],dp[200010],ans[200010],pos[200010];
struct node
{
int l,r,mx;
}tr[400010];
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline void pushup(int x)
{
int l=ch[x][0],r=ch[x][1];
sz[x]=sz[l]+sz[r]+1;
}
inline void build(int l,int r,int fa)
{
if(l>r)
return;
if(l==r)
{
sz[l]=1;
f[l]=fa;
if(l<fa)
ch[fa][0]=l;
else
ch[fa][1]=l;
return;
}
int mid=(l+r)>>1;
if(!root)
root=mid;
build(l,mid-1,mid);
build(mid+1,r,mid);
f[mid]=fa;
sz[mid]=1;
if(mid<fa)
ch[fa][0]=mid;
else
ch[fa][1]=mid;
pushup(mid);
}
inline int find(int rt,int k)
{
int l=ch[rt][0],r=ch[rt][1];
if(k==sz[l]+1)
return rt;
if(k<=sz[l])
return find(l,k);
else
return find(r,k-sz[l]-1);
}
inline void rotate(int x)
{
int y=f[x],z=f[y],k=ch[y][1]==x,w=ch[x][!k];
if(y!=root)
ch[z][ch[z][1]==y]=x;
ch[x][!k]=y;
ch[y][k]=w;
if(w)
f[w]=y;
f[y]=x;
f[x]=z;
pushup(y);
pushup(x);
}
inline void splay(int x,int rt)
{
while(f[x]!=rt)
{
int y=f[x],z=f[y];
if(f[y]!=rt)
{
if(ch[y][0]==x ^ ch[z][0]==y)
rotate(x);
else
rotate(y);
}
rotate(x);
}
if(!rt)
root=x;
pushup(x);
}
inline void ins(int k,int i)
{
int x=find(root,k),y=find(root,k+1);
splay(x,0);
splay(y,x);
val[++cnt]=i;
sz[cnt]=1;
ch[y][0]=cnt;
f[cnt]=y;
pushup(y);
splay(cnt,0);
}
inline void dfs(int rt)
{
if(!rt)
return;
if((!ch[rt][0])&&(!ch[rt][1]))
{
b[++cnt]=val[rt];
return;
}
dfs(ch[rt][0]);
b[++cnt]=val[rt];
dfs(ch[rt][1]);
}
inline void build1(int rt,int l,int r)
{
tr[rt].l=l;
tr[rt].r=r;
tr[rt].mx=0;
if(l==r)
return;
int mid=(l+r)>>1;
build1(rt<<1,l,mid);
build1(rt<<1|1,mid+1,r);
}
inline void update(int rt,int x,int y)
{
int l=tr[rt].l,r=tr[rt].r;
if(l==r)
{
tr[rt].mx=y;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
update(rt<<1,x,y);
else
update(rt<<1|1,x,y);
tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx);
}
inline int query(int rt,int le,int ri)
{
int l=tr[rt].l,r=tr[rt].r;
if(le<=l&&r<=ri)
return tr[rt].mx;
int mid=(l+r)>>1,res=0;
if(le<=mid)
res=max(res,query(rt<<1,le,ri));
if(mid+1<=ri)
res=max(res,query(rt<<1|1,le,ri));
return res;
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
a[i]=read()+1;
build(1,2,0);
cnt=2;
for(int i=1;i<=n;++i)
ins(a[i],i);
cnt=0;
dfs(root);
for(int i=1;i<=cnt-1;++i)
{
b[i]=b[i+1];
pos[b[i]]=i;
}
build1(1,1,n);
for(int i=1;i<=n;++i)
{
dp[i]=query(1,1,b[i])+1;
update(1,b[i],dp[i]);
}
for(int i=n;i>=1;--i)
{
ans[i]=query(1,1,n);
update(1,pos[b[i]],0);
}
for(int i=1;i<=n;++i)
printf("%d\n",ans[i]);
return 0;
}