DSA2021秋 PA1 範圍查詢Range 解題思路及程式碼
阿新 • • 發佈:2021-08-20
解題思路
本題有兩個解法
正常(課程期望)解法:將數軸座標排序後,二分查詢到兩個點,下標相減即可
字首和:將座標直接作為陣列下標,值為[0,i]範圍內存在點的個數。查詢時直接取出邊界點對應的值相減即可
正常解法
- 這裡使用快排將座標排序
- 二分查詢到對應的點,並將下標相減
#include <cstdio> #include <cctype> #define MAXN 500000 int axis[MAXN]; template <typename T> inline T readstdin() //加快IO的讀函式 { T input = 0; short sign = 1; char ch = 0; while (!isdigit(ch)) { if(ch == '-') sign = -1; ch = getchar(); } while (isdigit(ch)) { input = (input << 3) + (input << 1) + (ch - '0'); ch = getchar(); } return input * sign; } int binSearch( int n, int e) //二分查詢到[0,n]範圍內的,不大於e的最大值 { int lo = 0, hi = n; while (lo<hi) { int mi = (lo+hi)>>1; (e<axis[mi]) ? hi=mi : lo = mi + 1; } return --lo; } int getpartition(int lo,int hi){ //用於快排 int mi=axis[lo]; while(lo<hi) { while(lo<hi&&mi<=axis[hi]) hi--; axis[lo]=axis[hi]; while(lo<hi&&axis[lo]<=mi) lo++; axis[hi]=axis[lo]; } axis[lo]=mi; return lo; } void quicksort(int lo,int hi){ //快排 if(lo<hi) { int mi=getpartition(lo,hi); quicksort(lo,mi-1); quicksort(mi+1,hi); } } int main(int argc, char const *argv[]) { int n = readstdin<int>(); int m = readstdin<int>(); for (int i = 0; i < n; i++) { axis[i] = readstdin<int>(); } quicksort(0,n-1); int a, b; for (int i = 0; i < m; i++) { a = readstdin<int>()-1; b = readstdin<int>(); int t1 = binSearch(n,a); int t2 = binSearch(n,b); printf("%d\n",t2-t1); } return 0; }
字首和
- 初始化:將每個輸入的數軸座標直接作為陣列的下標,若該處有點,則值置為1,否則為0
- 生成字首和:axis[i] = axis[i-1] 即每個點的值為[0,i]中有效點的個數
- 計算:接收輸入後直接取出對應下標的值相減即可
#include <cstdio> #include <cctype> #define MAXN 10000001 int axis[MAXN] = {0}; template <typename T> inline T readstdin() { T input = 0; short sign = 1; char ch = 0; while (!isdigit(ch)) { if(ch == '-') sign = -1; ch = getchar(); } while (isdigit(ch)) { input = (input << 3) + (input << 1) + (ch - '0'); ch = getchar(); } return input * sign; } int main(int argc, char const *argv[]) { int n = readstdin<int>(); int m = readstdin<int>(); for (int i = 0; i < n; i++) //初始化 axis[readstdin<int>()] = 1; for (int i = 1; i < MAXN; i++) //生成字首和,即統計[0,i]的點總數 axis[i] += axis[i-1]; for (int i = 0; i < m; i++) { int a = readstdin<int>() - 1; int b = readstdin<int>(); printf("%d\n",axis[b]-axis[a]); } return 0; }
踩坑
- 最開始題目描述裡給的示例讓我一度以為座標是按序輸入的
- 即使二分查詢到了對應的下標,相減時也要仔細考慮各種情況並做出修補(+1-1之類的)
- 字首和長知識了