咕了一个月后来补题解。
第一眼支配对,然后没有第二眼了。
- 给出序列 (a1,…,an)。q 次询问 l,r,求 l≤i<j<k≤r 且存在以 ai,aj,ak 为三边长度的三角形的三元组 (i,j,k) 的 ai+aj+ak 最小值。
- n≤2.5×105,q≤5×105,ai≤107。
考虑按照二进制最高位将值域划分成若干个块,记
Bm=[2m,2m+1)。设值域为
V。
显然不用考虑
(i,j,k) 之间的大小关系,只要求她们不同且都在区间里面就一定可以将三元组写成递增的形式。注意到同块中任意三个元素均能作为三角形边长,因此对于每个询问,考虑找到最小的
m 使得
(al,…,ar) 在
Bm 中有
≥3 个元素。此时选取前三小值即可。线段树维护之,合并可以看成左右儿子信息归并。
这里可以考虑从小到大枚举每个块,再枚举询问,更新所有未被标记且在她中有
≥3 个元素的询问,然后标记这个询问。每个询问至多被标记一次,这时才会触发查询,因此时间复杂度为
O(qlogn)。
对于剩下的方案,如果想要更优,则必须至少存在一个
<2k 的元素。判断区间中某块内的元素个数可以先预处理该块内元素的前缀出现次数然后前缀相减。枚举每个块时都要处理一次,时间复杂度为
O(nlog∣V∣)。
-
注意到找到的是最小的
m 使得
(al,…,ar) 在
Bm 中有
≥3 个元素,因此对于编号为
[1,m) 的块,
(al,…,ar) 中的元素在其中的出现次数
≤2,即前
m−1 个块总共只有
O(log∣V∣) 个元素。先把她们全部找出来。可以考虑维护每个位置前 / 后(包含这个位置)第一个块内元素(前驱 / 后继),然后找
l 的后继和
r 的前驱即可。注意仅有
1 个元素时不要重复找。可以对于每个询问维护一个容器,枚举到每个块时,若
(al,…,ar) 中的元素在其中的出现次数
≤2,就找出
O(1) 个元素插入对应询问的容器里。还需要有序。但是从小到大枚举值域块已经保证块间的顺序了,只要在插入
O(1) 个元素时判断大小关系即可。
不妨认为
ai≤aj≤ak,则
ai≤aj<2m。若
(i,j,k) 能产生贡献,则区间中一定不存在
(aj,ak) 内的元素,不然最长边更换成她一定更优。换言之
k 一定是区间中除了
ai,aj 以外最小的
≥aj 的元素。那么
ak 一定在找出来的
O(log∣V∣) 个元素中或者在
(al,…,ar) 内
Bk 中最小的元素。若
(al,…,ar) 内没有
Bk 中的元素则不用考虑,因为
k 以后的块中的元素是无法和
ai,aj 产生贡献的。
记找出来的元素集合非降排序后为
(s1,…,st),枚举
su 作为
aj,则
ak=su+1。此时需要找到最小的
v 使得
sv>su+1−su。注意到
u 递增时若
su+1−su 也递增,则
aj,ak 两条边长度变大,
ai 这条边的限制也变大,一定不优。因此只要考虑
su+1−su 为前缀最小值的情况,此时她单调递减,因此
sv 也单调不升,用双指针维护即可。
每个询问仅在找到对应的
m 后才会触发双指针统计,因此时间复杂度为
O(qlog∣V∣)。
-
若仅有
1 个
<2m 的元素。
此时
ai 是最短边。考虑枚举这个元素
ai 在第
w 块。可以在枚举每一块的时候处理其中的所有元素。记
i 前第
x 个与
ai 同块的元素位置为
prex,
i 后第
x 个同块元素位置为
nxtx,则仅需要考虑
(pre2,nxt2) 内的
j,k,否则若一个询问需要用到这之外的
j,k 构成的
(i,j,k) 的询问,则至少包含
pre2,pre1,i 或
i,nxt1,nxt2 这三个
Bw 内的元素。而
ai 已经是最短边了,所以
aj,ak≥2w。则此时
(i,j,k) 这个三元组一定不如
Bw 块内前三小值优。而满足在询问区间中有至少三个元素的块
b 一定
≤w。因此
(i,j,k) 就没有贡献了。
而对于
Bw 内的元素而言
∣(pre2,nxt2)∣ 的总和是
O(n) 的,考虑每对相邻的同块元素的间距只会在
O(1) 个区间中产生贡献。而间距的总和是
O(n) 的。那么对于所有块,区间长度总和就是
O(nlog∣V∣)。
这时就可以直接枚举区间内大于
ai 的元素了。钦定
ak 为
aj,ak 中较大元素,若
aj=ak,则钦定
ak 为靠右的元素。令
ex=⌊aiax⌋,则
(i,j,k) 合法的
必要条件 是
ek−ej≤1。
若
ek=ej,则任意
(i,j,k) 都可行。直接把所有点对找出来不可接受,考虑找支配对。对于两个
本质不同 的点对,称
(i,j1,k1) 支配了
(i,j2,k2) 当且仅当
min{j2,k2}≤min{j1,k1}≤max{j1,k1}≤max{j2,k2} 且
ai+aj1+ak1≤ai+aj2+ak2。容易发现若一个点对被支配,则她对任何一个询问都没有贡献,因为若她在询问的区间内,则支配她的点对也在询问的区间内,且和更小。我们发现
有贡献的点对一定满足在大于 ai 且 ek=ej 的位置中,aj 是 k 左边第一个 ≤ak 的元素,或 k 右边第一个 <ak 的元素。给出前者的证明:
假使存在
j<p<k 使得
ai<aj,ap≤ak,若
ap<aj,则
(i,p,k) 支配了
(i,j,k);否则
(i,j,p) 支配了
(i,j,k)。后者的证明类似。
那么就可以枚举
k,然后对于每种
ek 维护单调栈就可以得到
j 的位置了。
若
ek=ej+1,则有贡献的点对一定满足
j 一定是
k 左 / 右第一个
ej=ek−1 的位置。给出在左边情况的证明:假使存在
j<p<k 使得
ej=ep=ek−1,则
(i,j,p) 支配了
(i,j,k),右边的情况类似。
此时,我们发现对于每个
ai 的区间内的位置
k,都找出了关于她的
O(1) 个可能有贡献的点对,因此总共有
O(nlog∣V∣) 个点对。对于一次询问只需要考虑这些点对即可,相当于查询
min{i,j,k}≥l,max{i,j,k}≤r 的点对中
ai+aj+ak 的最小值,直接扫描线配合树状数组维护即可。
到这里基本结束了。时间复杂度为
O((nlog∣V∣+q)log∣V∣),空间复杂度为
O(qlog∣V∣+∣V∣)。如果扫描线时使用高级点的数据结构可以做到更优时间复杂度。空间带
∣V∣ 的原因是对于每种
ek 开了单调栈,如果离散化可以做到更优。
然后我的实现被卡常了,加了指令集也会不时被卡。联系出题人要求时限增大
0.5 s 未果。建议被卡常的找个夜深人静的时候多交几发试试。