传送门
一道平衡树好题
因为每次插入的数都是最大的数,所以我们只需要找到插入位置pos的前缀中的LIS,就可以得到此次插入的答案。再把这个答案和全局最大值比较就是此次操作的答案。如何维护一个前缀的LIS就是本题需要实现的操作。
有的题解用了线段树+平衡树维护这个前缀LIS,但其实只使用一个平衡树就够了,具体做法:
考虑按大小分裂的treap,节点中记录一个val,代表该位置结尾的LIS,以及记录一个mx代表该位置前缀的LIS。为了维护前缀的LIS,我尝试过几种错误的方式:
- 乱搞一通
- 维护的mx只包含了左子树(区间操作的treap和线段树很像但又很不一样)
- 只维护了mx,没有维护val
第二和第三的错误让我对treap有了更深的认识,第二种方法的错误是很显然的,平衡树内部的结构不代表左子树就是左区间,要维护左区间需要用其他的方法。
仔细思考一下split的过程,是不断的把子树划分到x树上,这个x树,就是我们需要的前缀区间,那么所有的信息都可以在split的过程中保留下来。在每次split的过程中,我们记录一个mx维护当次分裂的前缀LIS。siz为此次分裂的大小。如果siz > fhq[lson(now)].siz,说明now的整颗左子树都是我们需要的区间。此时可以用fhq[lson(now)].mx和fhq[now].val(注意此时不是mx,具体原因可以自行思考)和下一次的split来更新mx。否则就只用下一次的split更新。这样就能正确的维护出前缀LIS了。
#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#define lson(i) fhq[i].l
#define rson(i) fhq[i].r
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline void read(int &a){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
a = x*f;
}
struct Node{
int l,r,siz,key,val,mx;
}fhq[N];
int tot;
std::mt19937 rnd(time(0));
int newnode(int val){
fhq[++tot].val = val;
fhq[tot].mx = val;
fhq[tot].siz = 1;
fhq[tot].key = rnd();
return tot;
}
void update(int now){
fhq[now].siz = fhq[lson(now)].siz + fhq[rson(now)].siz + 1;
fhq[now].mx = max(fhq[now].val,max(fhq[rson(now)].mx,fhq[lson(now)].mx));
}
int split(int now,int siz,int &x,int &y){
if(!now){
x = y = 0;
return 0;
}
int mx = 0;
if(fhq[lson(now)].siz < siz){
x = now;
mx = split(rson(now),siz-fhq[lson(now)].siz-1,rson(now),y);
mx = max(mx,max(fhq[lson(now)].mx,fhq[now].val));
}
else{
y = now;
mx = max(mx,split(lson(now),siz,x,lson(now)));
}
update(now);
return mx;
}
int merge(int x,int y){
if(!x || !y) return x+y;
if(fhq[x].key >= fhq[y].key){
rson(x) = merge(rson(x),y);
update(x);
return x;
}
else{
lson(y) = merge(x,lson(y));
update(y);
return y;
}
}
int root,x,y,z;
int main(){
int n;
cin >> n;
int ans = 0;
fir(i,1,n){
int v;
cin >> v;
if(!v)
root = merge(newnode(1),root),ans = max(ans,1);
else{
int mx = split(root,v,x,y);
ans = max(ans,mx+1);
root = merge(merge(x,newnode(mx+1)),y);
}
cout << ans << endl;
}
return 0;
}