A
b
o
u
t
:
About:
About:主席树的由来
一位名字缩写为
h
j
t
hjt
hjt的
D
a
l
a
o
Dalao
Dalao前国家领导人在考场上的
y
y
yy
yy
有请经典例题的
D
e
s
c
r
i
b
e
:
Describe:
Describe:
给定N个整数构成的序列,对于指定的闭区间查询其区间内的第K小值。
好像和可持久化毫无关系
Q
A
Q
QAQ
QAQ
我会权值线段树!
我们发现它没法维护原始区间信息。
那就让它能维护!
建立
N
N
N棵值域相同的线段树,其中
S
e
g
i
Seg_{i}
Segi储存了
A
[
1
,
i
]
A_{[1,i]}
A[1,i]的信息。
值域相同意味着它们大小相同
于是它们的信息可以互相加减。(很重要的性质!
对于区间
[
l
,
r
]
[l,r]
[l,r],
S
e
g
r
Seg_{r}
Segr的
[
a
,
b
]
[a,b]
[a,b](值域) 节点减去
S
e
g
l
−
1
Seg_{l - 1}
Segl−1的
[
a
,
b
]
[a,b]
[a,b]节点就可以得到
[
a
,
b
]
[a,b]
[a,b]在
[
l
,
r
]
[l,r]
[l,r]中的频率辣!
但如果我们开
N
N
N棵树
R
e
s
u
l
t
Result
Result:
M
L
E
MLE
MLE
要解决这个问题,我们需要尽量利用共同信息。
发现
S
e
g
i
−
1
Seg_{i-1}
Segi−1和
S
e
g
i
Seg_{i}
Segi相差的只是
A
i
A_{i}
Ai插入时经过的
l
o
g
2
N
log_{2}N
log2N个节点
于是我们可以共用未修改的节点!
/
/
//
//当然我们需要储存下
R
o
o
t
i
Root_{i}
Rooti以访问每棵树
!
!
!
(应该没人不知道吧…但我太菜了还是要啪叽几句
就像这样:(图先咕着…反正也没人看
/
/
//
//有人看了
C
a
l
l
Call
Call我吧
理解了就可以方便的写出代码
初始这样建树,函数的返回值为 R o o t 0 Root_{0} Root0
int Build(int l,int r)
{
int now = ++cnt;
if (l < r)
{
int mid = (l + r) / 2;
L[now] = Build(l,mid);
R[now] = Build(mid + 1,r);
}
return now;
}
然后这样插入节点:
int Add_Node(int l, int r, int k, int val)
{
int now = ++cnt;
L[now] = L[k], R[now] = R[k], Sum[now] = Sum[k] + 1;
if (l == r) return now;
int mid = (l + r) / 2;
if (val <= mid) L[now] = Add_Node(l, mid, L[k], val);
else R[now] = Add_Node(mid + 1, r, R[k], val);
return now;
}
求答案时注意:如果递归到右子树要减去 S S S
int Query(int Ra, int Rb, int l, int r, int rk)
{
if (l == r) return l;
int S = Sum[L[Rb]] - Sum[L[Ra]];
int mid = (l + r) / 2;
if (S >= rk) return Query(L[Ra], L[Rb], l, mid, rk);
else return Query(R[Ra], R[Rb], mid + 1, r, rk - S);
}
别忘了离散化!(注意
A
n
s
Ans
Ans
输出
A
n
s
Q
u
e
r
y
Ans_{Query}
AnsQuery就好
bool cmp(A u, A v){return u.val < v.val;}
void init()
{
for (int i = 1; i <= N; i++) a[i].val = x[i], a[i].pos = i;
std::sort(a + 1, a + N + 1, cmp);
a[0].val = -1;
for (int i = 1; i <= N; i++)
{
if (a[i].val != a[i - 1].val) RN++;
y[a[i].pos] = RN;
Ans[RN] = a[i].val;
}
}
查资料时发现@BestFy有更好的离散化写法
m = unique(b+1, b+1+n)-b-1;
N
O
I
P
NOIP
NOIP可以用的黑科技!
学一学学一学
鸣谢:参考了
L
u
o
g
u
Luogu
Luogu的大佬们的题解
谢谢他们让
J
v
R
u
o
JvRuo
JvRuo我和
D
a
l
a
o
Dalao
Dalao的其他人学会了主席的树!