/*我的首要看法是先进行排序,采用复杂度为O(nlogn)的排序算法,如堆排序,之后再用二分查找找到在范围内的最大数和最小数的位置,再运算得到数量(当然要设置标志位防止个数为0)每一次操作复杂度为O(logn),总复杂度为O((n + q)logn)。
*/
#include <stdio.h>
#include <stdlib.h>
//交换数组两个元素的位置的函数
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
//下沉操作的实现
void sink(int *a, int n, int i){
while(1){
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
//判断左右节点是否大于根节点,如果大于,谁更大?
if(left < n && a[left] > a[largest]){
largest = left;
}
if(right < n && a[right] > a[largest]){
largest = right;
}
//已经下沉到最底部了,不需要再次下沉
if(largest == i){
break;
}
//交换较大的子节点与根节点的值,并进行下一次循环,对换下去后的结点进行下沉
else{
swap(a + i, a + largest);
i = largest;
}
}
}
//堆排序的函数
void heap_sort_sl(int *a, int n ){
//堆化操作,形成大顶堆
//从最后一个非叶节点开始,向前对每一个结点进行下沉操作
for(int i = n / 2 - 1; i >= 0; i --){
sink(a, n, i);
}
//排序,每次取堆顶结点,与堆最后一个结点做交换,并使得堆长度减1,再让堆顶元素下沉,直到堆缩小到大小为1
for(int i = n - 1; i > 0; i --){
swap(a, a + i);
sink(a, i, 0);
}
}
int main() {
//读取数据
int n,q;
scanf("%d %d\n",&n,&q);
int *a = (int *)malloc(sizeof(int) * n);
if(a == NULL){
printf("Failed Malloc!\n");
return -1;
}
for(int i = 0; i < n; i ++){
scanf("%d", a + i);
}
int **lr = (int **)malloc(sizeof(int *) * q);
if(lr == NULL){
printf("Failed Malloc!\n");
return -1;
}
for(int i = 0; i < q; i ++){
lr[i]= (int *)malloc(sizeof(int) * 2);
if(lr[i] == NULL){
printf("Failed Malloc!\n");
return -1;
}
scanf("%d %d\n",lr[i],lr[i] + 1);
}
heap_sort_sl(a, n);//排序数组,从小到大
//处理q行
for(int i = 0; i < q; i ++){
//取l,r的值
int l = lr[i][0];
int r = lr[i][1];
//设置两个端点
int low = 0;
int high = n - 1;
//rl和rh用来存储范围内的最大数和最小数
int rl = -1;
int rh = n + 1;
int flag = 0;//设置标志位,若flag为0,则个数为0
//进入第一个循环找出范围内的最大数
while(low <= high){
int mid = low + (high - low) / 2;
if(a[mid] <= r && a[mid] >= l){
flag = 1;//有数在范围内,标志位置1
rh = mid;
low = mid + 1;
}
else{
if(a[mid] > r){
high = mid - 1;
}
else{
low = mid + 1;
}
}
}
//两个端点复位
low = 0;
high = n - 1;
//进入第二个循环找出范围内的最小数
while(low <= high){
int mid = low + (high - low) / 2;
if(a[mid] <= r && a[mid] >= l){
flag = 1;//有数在范围内,标志位置1
rl = mid;
high = mid - 1;
}
else{
if(a[mid] > r){
high = mid - 1;
}
else{
low = mid + 1;
}
}
}
//最大数减去最小数加1就是区间中的元素个数
int num = rh - rl + 1;
if(!flag){
num = 0;
}
printf("%d\n",num);
}
//释放空间
free(a);
free(lr);
return 0;
}