裸题?对于每一个节点维护前面第一个与它相同的位置,假设是
p
r
e
i
pre_i
prei,那么询问
[
l
,
r
]
[l,r]
[l,r]相当于是求:
∑
i
=
l
r
i
−
m
a
x
j
≤
l
(
p
r
e
j
,
l
−
1
)
\sum_{i=l}^ri-max_{j\le l}(pre_j,l-1)
i=l∑ri−maxj≤l(prej,l−1)
考虑这个东西其实就是把
l
−
1
l-1
l−1带进
[
l
,
r
]
[l,r]
[l,r]中,求一个前缀
m
a
x
max
max的单调栈,每个位置的最大值之和。
因此我们有一种用线段树维护最大值的方法。
考虑将
v
v
v带进
[
l
,
r
]
[l,r]
[l,r]求前缀最大值的时候,如果
v
≤
m
a
x
(
l
,
m
i
d
)
v\le max(l,mid)
v≤max(l,mid),那么走出
[
l
,
m
i
d
]
[l,mid]
[l,mid]之后的最大值就是
m
a
x
(
l
,
m
i
d
)
max(l,mid)
max(l,mid),因此我们可以对于线段树上每一个节点维护
m
a
x
(
l
,
m
i
d
)
max(l,mid)
max(l,mid)带入
[
m
i
d
+
1
,
r
]
[mid+1,r]
[mid+1,r]的贡献,然后往左区间走。
如果
v
>
m
a
x
(
l
,
m
i
d
)
v>max(l,mid)
v>max(l,mid),那么
[
l
,
m
i
d
]
[l,mid]
[l,mid]内的点都被跳过了,贡献直接求出,然后往右区间走。
这样求解一个
v
v
v在区间
[
l
,
r
]
[l,r]
[l,r]的贡献是
log
2
\log^2
log2的。
修改维护同样也是
log
2
\log^2
log2的。
还有一种稍微复杂一点的
O
(
n
log
n
)
O(n\log n)
O(nlogn)方法。
考虑离线,按照时间建一个线段树,前往后枚举序列位置
i
i
i,维护不同时间的
m
a
x
j
≤
i
(
p
r
e
j
)
max_{j\le i}(pre_j)
maxj≤i(prej),考虑当前位置在当前时间分成了若干段,通过打区间max即可完成总共
O
(
q
)
O(q)
O(q)次修改。