其他分享
首页 > 其他分享> > 二分与前缀和

二分与前缀和

作者:互联网

有一个已经按升序排好序的数组,求某个数在数组中出现的下标区间。即,若这个数在数组中出现一次或多次,就给出这个范围。

#include <iostream>
using namespace std;
const int maxn = 100005;
int n, q, x, a[maxn];
int main() {
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; i++)    scanf("%d", &a[i]);
	while (q--) {
		scanf("%d", &x);
		int l = 0, r = n - 1;
		while (l < r) {
			int mid = l + r >> 1;
			if (a[mid] < x)  l = mid + 1;
			else    r = mid;
		}
		if (a[l] != x) {
			printf("-1 -1\n");
			continue;
		}
		int l1 = l, r1 = n;
		while (l1 + 1 < r1) {
			int mid = l1 + r1 >> 1;
			if (a[mid] <= x)  l1 = mid;
			else    r1 = mid;
		}
		printf("%d %d\n", l, l1);
	}
	return 0;
}

设区间为 [left,right]。
首先用二分法求区间 left。对应代码:

int l = 0, r = n - 1;
while (l < r) {
	int mid = l + r >> 1;
	if (a[mid] < x) l = mid + 1;
	else r = mid;
}

初始时 l 和 r 处都有值。mid 的值靠近 l。

求右边界:

int l1 = l, r1 = n;
while (l1 + 1 < r1) {
	int mid = l1 + r1 >> 1;
	if (a[mid] <= x) l1 = mid;
	else r1 = mid;
}

直接在刚才的基础上,用 l 作为左边界(l 本来就是左边界嘛,如果要一般化就还是 l1=0),r1 从没有值的 n 处开始(总范围是 [0,n-1])。
我们的目标是让 l1 成为右边界。同时,我们要保证 r1 永远是大于 x 的。

标签:二分,r1,int,mid,while,l1,边界,前缀
来源: https://www.cnblogs.com/preccrep/p/16377190.html