题目要求动态插入点并求序列
L
I
S
LIS
LIS。
首先LIS的递推公式:
d
p
[
i
]
=
m
a
x
(
d
p
[
j
]
)
+
1
,
j
<
i
,
a
j
<
a
i
dp[i]=max(dp[j])+1 , j<i,a_j<a_i
dp[i]=max(dp[j])+1,j<i,aj<ai
发现这道题动态插入的点的权值是递增的。
因此
a
j
<
a
i
a_j<a_i
aj<ai的条件就不用管了。
问题转化为询问前面所有位置比当前位置小的dp值中的最大值+1。
怎么维护呢?动态插入节点,首先想到vector qwq
然而这是平衡树专题训练
czh:那你为什么不重复数字那一题用了map
zyd:因为我蒻qwq
所以建一棵非旋
T
r
e
a
p
Treap
Treap来维护之前的
d
p
dp
dp值。
然后这里
s
p
l
i
t
split
split操作要改一下:
普通的
F
H
Q
FHQ
FHQ
T
r
e
a
p
Treap
Treap的操作
s
p
l
i
t
split
split是按照权值分为两棵树。
但是这里不是对权值有要求,而是要求位置小于当前位置。
所以这里按照子树大小分成两棵树。
其他操作和普通非旋Treap一致qwq
代码
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
namespace I_Love {
const int Size=100005;
int n,tot,dp[Size];
#define lc(x) tree[x].ls
#define rc(x) tree[x].rs
struct node {
int ls,rs;
int pri;
int val;
int siz;
int id;
} tree[Size];
inline void Pushup(int x) {
tree[x].siz=tree[lc(x)].siz+tree[rc(x)].siz+1;
tree[x].val=max(max(tree[lc(x)].val,tree[rc(x)].val),dp[tree[x].id]);
}
inline int New(int i,int v) {
dp[i]=v;
tree[++tot].val=v;
tree[tot].siz=1;
tree[tot].id=i;
tree[tot].pri=rand();
return tot;
}
int Merge(int x,int y) {
if(!x || !y) return x|y;
if(tree[x].pri<tree[y].pri) {
rc(x)=Merge(rc(x),y);
Pushup(x);
return x;
} else {
lc(y)=Merge(x,lc(y));
Pushup(y);
return y;
}
}
void Split(int i,int k,int &x,int &y) {
if(!i) {
x=y=0;
} else {
if(tree[lc(i)].siz>=k) {
y=i;
Split(lc(i),k,x,lc(i));
} else {
x=i;
Split(rc(i),k-tree[lc(i)].siz-1,rc(i),y);
}
Pushup(i);
}
}
void Fujibayashi_Ryou() {
n=read();
int root=0;
for(re i=1; i<=n; i++) {
int a=0,b=0;
Split(root,read(),a,b);
//加入一个节点
a=Merge(a,New(i,tree[a].val+1));
//把分裂出来的两棵树合并回去
root=Merge(a,b);
printf("%d\n",tree[root].val);
}
}
}
int main() {
I_Love::Fujibayashi_Ryou();
return 0;
}
/*
9 3
2 4 3 6 1 5 8 9 7
3 5
2 6
1 4
*/