二分练习题10 查找给定范围内数的个数 题解

题目描述

现在告诉你一个长度为 \(n\) 的有序数组 \(a_1, a_2, ..., a_n\) ,以及 \(q\) 次询问,每次询问会给你两个数 \(x_1\)\(x_2\) ,对于每次询问,你需要确定在数组中满足 \(x_1 \le a_i \le x_2\) 的元素 \(a_i\) 的个数。

输入格式

输入的第一行包含一个整数 \(n(1 \le n \le 100000)\) ,用于表示数组中元素的个数。
输入的第二行包含 \(n\) 个整数,两两之间有一个空格,用于表示数组中的元素 \(a_1, a_2, ..., a_n(1 \le a_i \le 10^9,并且 a_1 \le a_2 \le ... \le a_n)\)
输入的第三行包含一个整数 \(q(1 \le q \le 100000)\) ,用于表示询问的次数。
接下来 \(q\) 行,每行包含两个整数 \(x_1,x_2(1 \le x_1 \le x_2 \le 10^9)\) ,表示要询问的数。

输出格式

对于每一次询问的 \(x_1,x_2\) ,输出数组中满足 \(x_1 \le a_i \le x_2\) 的元素 \(a_i\) 的个数。每个输出结果占单独的一行。

样例输入

5
1 3 5 7 9
3
3 6
2 100
11 13

样例输出

2
4
0

题目分析

这道题目乍看起来有点麻烦,但是其实也是可以使用二分算法来解决的。
不过我们这里需要使用两次二分,对于每一次询问 \(x_1,x_2\) ,我们需要:

  • 二分找到 \(\le x_1\) 的最小元素的坐标 \(i_1\)
  • 二分找到 \(\ge x_2\) 的最大元素的坐标 \(i_2\)

那么 \(i_2-i_1+1\) 就是我们的答案。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, q, x1, x2, a[maxn];
int solve() {
    int L = 1, R = n, i1 = -1, i2 = -1;
    while (L <= R) {    // 查找>=x1的最小坐标i1
        int mid = (L + R) / 2;
        if (a[mid] >= x1) {
            i1 = mid;
            R = mid - 1;
        }
        else L = mid + 1;
    }
    L = 1; R = n;
    while (L <= R) {    // 查找<=x2的最大坐标i2
        int mid = (L + R) / 2;
        if (a[mid] <= x2) {
            i2 = mid;
            L = mid + 1;
        }
        else R = mid - 1;
    }
    if (i1 == -1 || i2 == -1) return 0;
    return i2 - i1 + 1;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    cin >> q;
    while (q --) {
        cin >> x1 >> x2;
        cout << solve() << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zifeiynoip/p/11450641.html