1. 程式人生 > >(樹狀數組+離線查詢)HDU 4417 - Super Mario

(樹狀數組+離線查詢)HDU 4417 - Super Mario

blog 數組 string 個數 r++ dex 分塊 每次 class

題意:

給定一個數列,最多10萬次查詢l到r不超過h的數字的個數。

分析:

唉,太菜啦。

在線做法應該比較明顯,區間維護平衡樹,用線段樹套平衡樹,或者分塊套平衡樹,應該都能A,但是沒試過,只是BB,如有錯誤歡迎指正。

其實最方便的做法離線做法,太巧妙啦。

把數列按升序排列,把所有查詢按h升序排列。

每次查詢把比h的小的位置標記為1,查詢用bit的sum(r)-sum(l-1)即可

因為都是單調的,所以很方便。

其實很多沒有修改的區間問題都可以轉化成離線問題。

甚至於一些帶修改的題都可以離線。

這些題關鍵在於如何轉化,也關鍵在於做題者的腦洞。

代碼:

 1
#include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 7 8 using namespace std; 9 10 const int inf = 0x3f3f3f3f; 11 const int maxn = 100010; 12 13 int bit[maxn]; 14 int t, n, q; 15 16 int sum(int i) {
17 int s = 0; 18 while(i > 0) { 19 s += bit[i]; 20 i -= i & -i; 21 } 22 return s; 23 } 24 25 void add(int i, int x) { 26 while(i <= n) { 27 bit[i] += x; 28 i += i & -i; 29 } 30 } 31 32 struct Q { 33 int l, r, h;
34 int index; 35 } query[maxn]; 36 37 bool cmp(Q a, Q b) { 38 return a.h < b.h; 39 } 40 41 pair<int, int> a[maxn]; 42 int ans[maxn]; 43 44 int main() { 45 scanf("%d", &t); 46 int kase = 0; 47 while(t--) { 48 memset(bit, 0, sizeof(bit)); 49 scanf("%d%d", &n, &q); 50 for(int i = 1; i <= n; i++) { 51 scanf("%d", &a[i].first); 52 a[i].second = i; 53 } 54 for(int i = 0; i < q; i++) { 55 scanf("%d%d%d", &query[i].l, &query[i].r, &query[i].h); 56 query[i].l++, query[i].r++; 57 query[i].index = i; 58 } 59 sort(query, query + q, cmp); 60 sort(a + 1, a + n + 1); 61 int left = 1; 62 for(int i = 0; i < q; i++) { 63 while(left <= n && a[left].first <= query[i].h) { 64 add(a[left].second, 1); 65 left++; 66 } 67 int r = sum(query[i].r); 68 int l = sum(query[i].l - 1); 69 ans[query[i].index] = r - l; 70 } 71 printf("Case %d:\n", ++kase); 72 for(int i = 0; i < q; i++) { 73 printf("%d\n", ans[i]); 74 } 75 } 76 77 78 79 return 0; 80 81 }

(樹狀數組+離線查詢)HDU 4417 - Super Mario