樹狀陣列相關應用之區間包含問題
阿新 • • 發佈:2018-12-16
區間包含問題
對於一維區間問題一般是採用定一議二的方法 區間外包含問題:POJ-2481 對於此問題我們可以先按x升序排序(x值相同,y大的排在前面),保證之後輸入的區間的左端必在之前輸入區間之內,若x值相等,y降序,則之後輸入區間的右端必在之前輸入區間之內,那麼此題便轉化為對y求字尾陣列和問題
#include <iostream> #include <cstring> #include <stdio.h> #include <algorithm> #define MAXSIZE 100005 using namespace std; //使用名稱空間std struct cow { int no; //編號 int S, E; //區間 int num; //比其強壯奶牛數量 }; cow arry[MAXSIZE]; int val[MAXSIZE]; int main() { bool cmp(cow a, cow b); bool cmp_no(cow a, cow b); int lowbit(int x); void update_1(int val[], int i, int cal, int arry_num); int sum_pre_1(int val[], int i); int sum_between_1(int val[], int pre, int last); int flag; int begin=0, end=0; //記錄區間最大範圍,在此範圍內構建樹狀陣列 int pre, last; //記錄單個區間外的前方和後方奶牛數 while (~scanf("%d",&flag)) { if (!flag) break; memset(val, 0, sizeof(val)); begin = MAXSIZE; end = 0; for (int i = 1;i <= flag;i++) { arry[i].no = i; scanf("%d %d", &arry[i].S, &arry[i].E); begin = begin < arry[i].S ? begin : arry[i].S; end = end > arry[i].E ? end : arry[i].E; } begin++; //區間整體後移(避免區間左端為0的情況) end++; //資料輸入完成 sort(arry + 1, arry + flag + 1, cmp); //先將左端小的排在前,如果左端相等,再將右端大的排在前 //原陣列處理完畢 int temp = 0; //暫存器 for (int i = 1;i <= flag;i++) { if (arry[i].S==arry[i - 1].S&&arry[i].E == arry[i - 1].E&&i != 1) arry[i].num = temp; else { arry[i].num = sum_between_1(val, arry[i].E + 1, end); temp = arry[i].num; } update_1(val, arry[i].S + 1, 1, end); update_1(val, arry[i].E + 1, 1, end); } sort(arry + 1, arry + flag + 1, cmp_no); //陣列順序復原 printf("%d", arry[1].num); for (int i = 2;i <= flag;i++) printf(" %d", arry[i].num); printf("\n"); } return 0; } bool cmp(cow a, cow b) {//先將左端小的放在前,若左端相等,則將右端大的放在前 if (a.S != b.S) return a.S < b.S; else return a.E > b.E; } bool cmp_no(cow a, cow b) { return a.no < b.no; } int lowbit(int x) {//返回二進位制數最低位的1對應的數值 return x & (-x); //與運算 } //一維樹狀陣列 void update_1(int val[], int i, int cal, int arry_num) {//原陣列第i個元素加上cal,更新樹狀陣列相關元素,arry_num為原陣列的長度 //可直接用於樹狀陣列的建立 for (;i <= arry_num;i += lowbit(i)) val[i] += cal; } int sum_pre_1(int val[], int i) {//求arry陣列的前i項和 //val為樹狀陣列地址 int sum = 0; for (;i > 0;i -= lowbit(i)) //從後向前每次跳一個lowbit sum += val[i]; return sum; } int sum_between_1(int val[], int pre, int last) {//求原陣列arry在區間[pre-last]的和 return sum_pre_1(val, last) - sum_pre_1(val, pre - 1); }
區間內包含問題則按x降序,y升序排列,對y求字首陣列和即可