左边界查找模板
while (l < r) {
int mid = l + r >> 1; // 注意:没有 “+1”
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
作用:
找到数组中 第一个 >= x 的位置。若数组中有多个 x,则返回第一个 x 的位置(左边界)。
关键逻辑:
条件 q[mid] >= x: 当中间值 >= x 时,说明左边界可能在 mid 或更左侧,所以将右边界 r 设为 mid(保留 mid)。
否则 l = mid + 1: 当中间值 < x 时,说明左边界一定在 mid 右侧,所以将左边界 l 设为 mid + 1。
mid 计算方式:
mid = l + r >> 1(等价于 (l + r) / 2)是为了 向下取整,避免在 l 和 r 相邻时死循环。
最终结果:
循环结束时 l == r,且 q[l] 是第一个 >= x 的元素。若数组中无 x,则 l 是第一个 > x 的位置。
右边界查找模板
while (l < r) {
int mid = l + r + 1 >> 1; // 注意:有 “+1”
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
作用:
找到数组中 最后一个 <= x 的位置。若数组中有多个 x,则返回最后一个 x 的位置(右边界)。
关键逻辑:
条件 q[mid] <= x: 当中间值 <= x 时,说明右边界可能在 mid 或更右侧,所以将左边界 l 设为 mid(保留 mid)。
否则 r = mid - 1: 当中间值 > x 时,说明右边界一定在 mid 左侧,所以将右边界 r 设为 mid - 1。
mid 计算方式:
mid = l + r + 1 >> 1(等价于 (l + r + 1) / 2)是为了 向上取整,避免在 l 和 r 相邻时死循环。
最终结果:
循环结束时 l == r,且 q[l] 是最后一个 <= x 的元素。若数组中无 x,则 l 是最后一个 < x 的位置。
为什么两种模板的 mid 计算不同?
左边界模板:向下取整(mid = l + r >> 1
)确保 l 能正确向右收敛,避免死循环。
右边界模板:向上取整(mid = l + r + 1 >> 1
)确保 r 能正确向左收敛,避免死循环。
总结:
左边界模板:条件 >= x
+ 向下取整的 mid → 找第一个符合条件的。
右边界模板:条件 <= x
+ 向上取整的 mid → 找最后一个符合条件的。