def lower_bound(arr, l, r, x): """在数组 arr 的区间 [l, r) 中找到第一个大于等于 x 的元素的索引""" while l < r: mid = (l + r) // 2 if arr[mid] < x: l = mid + 1 else: r = mid return l def upper_bound(arr, l, r, x): """在数组 a 的区间 [l, r) 中找到第一个大于 x 的元素的索引""" while l < r: mid = (l + r) // 2 if arr[mid] <= x: l = mid + 1 else: r = mid return l def find_y(arr, op, l, r, x): """根据给出的option找到对应的y值""" # 最小的 y 使得 x≤y 的指针为 lower_bound 。 if op == 1: idx = lower_bound(arr, l, r, x) return arr[idx] if idx < r and arr[idx] >= x else -1 # 最小的 y 使得 x<y 的指针为 upper_bound 。 elif op == 2: idx = upper_bound(arr, l, r, x) return arr[idx] if idx < r else -1 # 最大的 y 使得 y<x 的指针为 lower_bound−1 。 elif op == 3: idx = lower_bound(arr, l, r, x) return arr[idx - 1] if idx > l else -1 # 最大的 y 使得 y≤x 的指针为 upper_bound−1 。 elif op == 4: idx = upper_bound(arr, l, r, x) return arr[idx - 1] if idx > l and arr[idx - 1] <= x else -1 for _ in range(0,m): op, left, right, x = map(int, input().split()) y = find_y(a, op, left, right, x) print(y)
lower_bound
和 upper_bound
函数是二分查找算法的两种变体,它们在有序数组中查找特定元素的索引。下面我将解释这两个函数中的 if
条件是如何工作的:
lower_bound 函数
lower_bound
函数用于找到第一个大于等于给定值 x
的元素的索引。
if arr[mid] < x:
:检查中间元素是否小于x
。如果是,则说明第一个大于等于x
的元素在mid
右侧(因为数组是有序的),所以我们更新左边界l
为mid + 1
。else:
:如果中间元素不小于x
,那么mid
可能就是我们要找的元素,或者第一个大于等于x
的元素在mid
的左侧。因此,我们将右边界r
更新为mid
。
通过这种方式,我们不断缩小搜索范围,直到找到第一个大于等于 x
的元素。
upper_bound 函数
upper_bound
函数用于找到第一个大于给定值 x
的元素的索引。
if arr[mid] <= x:
:检查中间元素是否小于等于x
。如果是,则说明第一个大于x
的元素在mid
右侧,所以我们更新左边界l
为mid + 1
。else:
:如果中间元素大于x
,那么mid
可能就是我们要找的元素,或者第一个大于x
的元素在mid
的左侧。因此,我们将右边界r
更新为mid
。
同样,我们通过这种方式不断缩小搜索范围,直到找到第一个大于 x
的元素。
总的来说,这两个函数的关键在于如何根据中间元素与目标值 x
的比较结果来调整搜索范围。lower_bound
在找到大于等于 x
的元素时停止,而 upper_bound
在找到大于 x
的元素时停止。这两个函数都返回左边界 l
,在二分查找结束时,l
就是我们要找的元素的索引(如果存在的话)。
操作 1 (op == 1
)
idx = lower_bound(arr, l, r, x)
: 使用lower_bound
函数找到第一个大于等于x
的元素的索引。return arr[idx] if idx < r and arr[idx] >= x else -1
: 如果找到的索引idx
在区间[l, r)
内,并且对应的元素大于等于x
,则返回该元素。否则,返回-1
。
操作 2 (op == 2
)
idx = upper_bound(arr, l, r, x)
: 使用upper_bound
函数找到第一个大于x
的元素的索引。return arr[idx] if idx < r else -1
: 如果找到的索引idx
在区间[l, r)
内,则返回该元素。否则,返回-1
。
操作 3 (op == 3
)
idx = lower_bound(arr, l, r, x)
: 使用lower_bound
函数找到第一个大于等于x
的元素的索引。return arr[idx - 1] if idx > l else -1
: 如果找到的索引idx
大于l
,则返回索引idx - 1
对应的元素。这是因为我们要找的是小于x
的最大元素。如果idx
等于l
,则说明没有找到小于x
的元素,返回-1
。
操作 4 (op == 4
)
idx = upper_bound(arr, l, r, x)
: 使用upper_bound
函数找到第一个大于x
的元素的索引。return arr[idx - 1] if idx > l and arr[idx - 1] <= x else -1
: 如果找到的索引idx
大于l
,并且索引idx - 1
对应的元素小于等于x
,则返回该元素。否则,返回-1
。
在每种操作中,我们都在寻找特定的元素,并使用 lower_bound
或 upper_bound
函数来确定该元素的索引。根据操作的不同,我们可能返回找到的元素,或者返回 -1
(如果没有找到符合条件的元素)。
n, m = map(int,input().split()) a = list(map(int, input().split())) def lower_bound(l, r, x): """在数组 arr 的区间 [l, r) 中找到第一个大于等于 x 的元素的索引""" while l < r: mid = (l + r) // 2 if a[mid] < x: l = mid + 1 else: r = mid return l def upper_bound(l, r, x): """在数组 a 的区间 [l, r) 中找到第一个大于 x 的元素的索引""" while l < r: mid = (l + r) // 2 if a[mid] <= x: l = mid + 1 else: r = mid return l for _ in range(0,m): op, left, right, x = map(int, input().split()) # 最小的 y 使得 x≤y 的指针为 lower_bound 。 if(op==1): idx = lower_bound(left,right,x) if(idx==right): print(-1) else: print(a[idx]) # 最小的 y 使得 x<y 的指针为 upper_bound 。 elif(op==2): idx = upper_bound(left,right,x) if(idx==right): print(-1) else: print(a[idx]) # 最大的 y 使得 y<x 的指针为 lower_bound−1 。 elif(op==3): idx = lower_bound(left,right,x) if(idx==left): print(-1) else: print(a[idx-1]) # 最大的 y 使得 y≤x 的指针为 upper_bound−1 。 else: idx = upper_bound(left,right,x) if(idx==left): print(-1) else: print(a[idx-1])