P4309 [TJOI2013] 最长上升子序列

P4309 [TJOI2013] 最长上升子序列

题目描述

给定一个序列,初始为空。现在我们将 1N 的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

数据范围:

100% 的数据 n105

说句闲话

应该没有那个神人想在线维护这玩意吧,毕竟两颗平衡树什么的还是太不可爱了。

solution:

我们先把所有操作离线然后用平衡树维护出最终的序列,再将每个数字所在位置映射到一个数组 ai 中,表示 i 在最终序列中的位置。

然后我们思考一下以前我们怎么 O(nlogn) 求 LIS 的:
维护一个数组,表示当前的 LIS 序列,然后二分一下当前点可以作为 LIS 上的哪个点然后优化一下。

但是我们发现对于本题,如果再用平衡树去维护这个东西貌似不太好写 (反正我debug写炸了,换了线段树)

但是我们发现使用线段树也同样可以做到 O(nlogn) 求LIS:

我们开一颗线段树,维护一下以某个数为结尾的 LIS 的长度最大值 len 。那么对于一个数 x 以该点为结尾的 LIS 长度就是 leni=1+maxi=1x1leni 然后我们再把 leni 更新到线段树上就好了。

然后这题就做完了。

Code:

#include<bits/stdc++.h>
const int N=1e5+5;
const int inf=1e9;
using namespace std;
int rd(){return rand()*rand()+17;}
struct FHQ_Treap{
int rt,cnt;
int fa[N];
struct Tree{
int ls,rs,val,siz,pri;
}t[N];
int Node(int val){t[++cnt]={0,0,val,1,rd()};return cnt;}
void pushup(int x)
{
t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;
if(t[x].ls)fa[t[x].ls]=x;
if(t[x].rs)fa[t[x].rs]=x;
}
void splite_siz(int x,int &a,int &b,int k)
{
if(!x){a=b=0;return ;}int tmp=t[t[x].ls].siz+1;
if(k>=tmp){a=x;splite_siz(t[x].rs,t[x].rs,b,k-tmp);}
else {b=x;splite_siz(t[x].ls,a,t[x].ls,k);}
pushup(x);
}
int merge(int x,int y)
{
if(!x||!y)return x|y;
if(t[x].pri<t[y].pri){t[x].rs=merge(t[x].rs,y);pushup(x);return x;}
else {t[y].ls=merge(x,t[y].ls);pushup(y);return y;}
}
int get_siz(int x)
{
if(!x)return 0;
int res=t[t[x].ls].siz+1;
while(fa[x])
{
if(t[fa[x]].rs==x)res+=t[t[fa[x]].ls].siz+1;
x=fa[x];
}
return res;
}
}T1;
int n,ans;
int a[N];
inline int Max(int x,int y){return x>y ? x : y;}
struct Segment_Tree{
#define ls x<<1
#define rs x<<1|1
struct Tree{
int val;
}t[N<<2];
inline void pushup(int x){t[x].val=Max(t[ls].val,t[rs].val);}
void upd(int x,int l,int r,int pos,int k)
{
if(l==r){t[x].val=Max(t[x].val,k);return;}
int mid=l+r>>1;
if(pos<=mid)upd(ls,l,mid,pos,k);
else upd(rs,mid+1,r,pos,k);
pushup(x);
}
int query(int x,int l,int r,int L,int R)
{
if(R<l||r<L)return 0;
if(L<=l&&r<=R){return t[x].val;}
int mid=l+r>>1,res=0;
if(L<=mid)res=Max(res,query(ls,l,mid,L,R));
if(mid<R) res=Max(res,query(rs,mid+1,r,L,R));
return res;
}
}T;
void work()
{
cin>>n;
for(int i=1,pos,a,b,c;i<=n;i++)
{
scanf("%d",&pos);
T1.splite_siz(T1.rt,a,b,pos);
T1.rt=T1.merge(T1.merge(a,T1.Node(i)),b);
}
for(int i=1;i<=n;i++)
{
a[i]=T1.get_siz(i);
}
for(int i=1;i<=n;i++)
{
int tmp=T.query(1,1,n,1,a[i])+1;
ans=Max(ans,tmp);
T.upd(1,1,n,a[i],tmp);
printf("%d\n",ans);
}
}
int main()
{
//freopen("P4309.in","r",stdin); freopen("P4309.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示