• 【Tsinghua OJ】范围查询(Range)问题


    【问题描述】
    数轴上有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×105
    对于次查询的区间[a, b],都有a ≤ b
    各点的坐标互异
    各点的坐标、查询区间的边界a、b,均为不超过10^7的非负整数
    时间:2s,内存:256MB


    【solution】先不废话,先贴源代码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 #define L 500005
     5 
     6 int a[L];
     7 
     8 int compare(const void *a, const void *b)
     9 {
    10     int *pa = (int*)a;
    11     int *pb = (int*)b;
    12     return (*pa) - (*pb);  
    13 }
    14 
    15 void swap(int &a, int &b)
    16 {
    17     int temp;
    18     temp = a;
    19     a = b;
    20     b = temp;
    21 }
    22 
    23 int find(int begin, int end, int ac)
    24 {
    25     int mid, left = begin, right = end;
    26     while (left <= right)
    27     {
    28         mid = left + ((right - left) >> 1);
    29         if (a[mid] >= ac) right = mid - 1;
    30         else left = mid + 1;
    31     }
    32     return left;
    33 }
    34 
    35 
    36 int main()
    37 {
    38     int n, m, i;
    39     scanf("%d %d
    ", &n, &m);
    40 
    41     for (i = 0; i < n; i++)
    42     {
    43         scanf("%d", &a[i]);
    44     }
    45 
    46     //refer to http://www.cnblogs.com/CCBB/archive/2010/01/15/1648827.html
    47     qsort(a, n, sizeof(int), compare);
    48 
    49     for (i = 0; i < m; i++)
    50     {
    51         int l, r, ans, lf, rt;
    52         scanf("%d %d", &l, &r);
    53 
    54         //make sure l <= r
    55         if (l > r)
    56         {
    57             swap(l, r);
    58         }
    59 
    60         rt = find(0, n - 1, r);
    61         lf = find(0, n - 1, l);
    62         ans = rt - lf;
    63         if (a[rt] == r) ans++;
    64         if (ans < 0) ans = 0;
    65 
    66         printf("%d
    ", ans);
    67     }
    68 }

    第一感觉都是这道题以前学的时候肯定做过,很简单,看到这个数据规模基本也就确定得用二分查找了。(反正看网上想先维护好线性数组再O(1)的查找是没混过去的)

    实际上,二分查找并没有看起来那么简单,尤其是具体写起来的时候,有很多细节与临界点的处理都得根据实际情况仔细斟酌。

    结合上述源代码,有几点值得注意的地方:
    1)qsort的用法,参考了:http://www.cnblogs.com/CCBB/archive/2010/01/15/1648827.html。 Tsinghua OJ 不支持 algorithm 库。
    2)倒数第三行代码(if (a[rt] == r) ans++;)实际上就是二分查找结合具体情况对答案的调整。不妨分上界和下界等于或者不等于a数组中的值分情况讨论,即可明白这一行的涵义。这也跟二分查找几个细节的处理相统一。
    3)二分查找函数中这一行:mid = left + ((right - left) >> 1);。一方面,位运算提高运算效率;另一方面,不直接用 (left + right) >> 1 防止计算过程中数字越界,进而导致数组下标越界。
    4)二分查找不要用递归形式。一是提高效率;二是防止堆栈溢出。


    [ by Maples7 ]
    [ Copyright @Maples7,转载请注明出处。 ]
  • 相关阅读:
    JavaScript 相关记录
    首页大图淡入淡出效果工具flexslider
    取消chrome浏览器下input和textarea的默认样式;html5默认input内容清除“×”按钮去除办法
    Hibernate入门笔记
    Servlet入门笔记
    父容器利用opacity设置透明后,子元素跟着变透明的解决方案
    overflow:hidden与margin:0 auto之间的冲突
    初识Android Studio
    首页图片滚动效果
    DIV宽度设置成100%,浏览器窗口缩小后,右边出现留白
  • 原文地址:https://www.cnblogs.com/maples7/p/4040062.html
Copyright © 2020-2023  润新知