这是学完邓公的数据结构第二章向量(vector)之后的problem assignment,直接贴出题目的text:
描述
数轴上有n个点,对于任一闭区间 [a, b],试计算落在其内的点数。
输入
第一行包括两个整数:点的总数n,查询的次数m。
第二行包含n个数,为各个点的坐标。
以下m行,各包含两个整数:查询区间的左、右边界a和b。
输出
对每次查询,输出落在闭区间[a, b]内点的个数。
样例
输入
5 2
1 3 7 9 11
4 6
7 12
输出
0
3
限制
0 ≤ n, m ≤ 5×10^5
对于每次查询的区间[a, b],都有a ≤ b
各点的坐标互异
各点的坐标、查询区间的边界a、b,均为不超过10^7的非负整数
时间:2 sec
内存:256 MB
思路比较简单,大体上就是先对输入的整一组点进行排序,随后对其进行查找,找到给定区间的左端点和右端点,然后计算落在其中的元素的数目。
有几个细节需要注意一下,这道题的排序如果采用类似二路归并排序这种复杂度为O(nlogn) 的排序算法,最后几个测试案例是要TLE(超时)的,所以这边我采用的是计数排序(复杂度为O(n),只要一趟循环就可以了),多开一个规模和输入规模相当的数组,用空间换时间;第二个要注意的是,如果这边采用的查找是邓俊辉的数据结构中采用的,即“返回一个不大于查找值的且在向量中秩最大的元素的位置”(白话就是待查找元素唯一时返回那个唯一的,待查找元素不唯一是返回最前面的,待查到元素找不到时返回小于它的最大元素)的话,要特判待查找元素小于数组最小元素的情形,因为这时候返回的秩是-1。
下面贴出完整版的AC代码:
#include <cstdio>
#define COUNTING_SORT_ARRAY_CAPACITY 10000001
class Vector
{
public:
Vector(int _size = 0) :m_size(_size)
{
m_elements = new int[m_size];
}
~Vector()
{
delete[] m_elements;
}
int size(void) {
return m_size;}
int& operator[] (int _rank) {
return m_elements[_rank];}
void sort(void) //通过牺牲空间换取时间,将向量元素的值映射到count数组的下标,下标对应的值记录出现次数
{
if (! ordered())