poj_2182 线段树/树状数组
題目大意
????n個數(shù)排成一排(不知道大小,只是占了一個位置),從a[1]到a[n]進(jìn)行遍歷,對于每個a[i],給出從a[1]到a[i-1]中小于a[i]數(shù)的個數(shù)。要求出 a[1]到a[n]中這n個數(shù)的相對順序。
題目分析
????對于每個數(shù) a[i], 給出了從 a[1] -- a[i-1]中小于a[i]的個數(shù) less[i].?
????從n到1逆序查看, less[n] 表示前n-1個數(shù)中小于a[n]的個數(shù),則可以確定a[n]的位置為 less[n] + 1?
類似的對于 i,為了確定a[i]在所有n個數(shù)中的序號,將這個任務(wù)分為兩部分:?
(1)在 a[1] -- a[i-1]中有多少個數(shù)小于a[i], 題目給出了為 less[i]?
(2)在a[i+1]---a[n]中有多少個數(shù)小于 a[i], 設(shè)為t
????則 a[i] 在所有n個數(shù)中的序號(按照從小到大排序)為 k = less[i] + t + 1
????但是,t并不好直接求出,則觀察k的性質(zhì)。對于a[i]在所有n個數(shù)中的位置k,1---k-1中包括 less[i]個在 a[1] -- a[i-1]中的元素,同時包括t個在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已經(jīng)確定了他們在整個n個數(shù)中的位置(我們是從后往前進(jìn)行計算的),則 1----k-1中就可以確定那t個元素的位置。
????為了確定k的位置,則設(shè)置一個數(shù)組b[1]--b[n],初始全部為0,從n到1統(tǒng)計,若a[i]的位置確定下來為p,則 b[p] = 1.則對于任意的k,b[1]---b[k]中1的個數(shù)表示 1----k中被占用的位置,0 的位置表示未被占用的位置。
????對于 a[i],找到某個k,使得其b[1]--b[k-1]中0的個數(shù)正好為 less[i]個,則k的位置就是 a[i]在整個n個數(shù)中的按照大小排序的位置
實現(xiàn)(c++)
1.?線段樹
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h>#define MAX_COW_NUM 80010 #define MAX_NODE_NUM 4*MAX_COW_NUMint gLess[MAX_COW_NUM]; int gPos[MAX_COW_NUM]; struct Node{int beg;int end;int sum_zero;int Mid(){return (beg + end) >> 1;} }; Node gNodes[MAX_NODE_NUM]; void BuildTree(int beg, int end, int index){gNodes[index].beg = beg;gNodes[index].end = end;if (beg == end){gNodes[index].sum_zero = 1;return;}int left = 2 * index + 1;int right = 2 * index + 2;int mid = (beg + end) >> 1;BuildTree(beg, mid, left);BuildTree(mid + 1, end, right);gNodes[index].sum_zero = gNodes[left].sum_zero + gNodes[right].sum_zero; } //對于每個數(shù) a[i], 給出了從 a[1] -- a[i-1]中小于a[i]的個數(shù) less[i]. //從n到1逆序查看, less[n] 表示前n-1個數(shù)中小于a[n]的個數(shù),則可以確定a[n]的位置為 less[n] + 1 //類似的對于 i,為了確定a[i]在所有n個數(shù)中的序號,將這個任務(wù)分為兩部分: //(1)在 a[1] -- a[i-1]中有多少個數(shù)小于a[i], 題目給出了為 less[i] //(2)在a[i+1]---a[n]中有多少個數(shù)小于 a[i], 設(shè)為t//則 a[i] 在所有n個數(shù)中的序號(按照從小到大排序)為 k = less[i] + t + 1//t 并不好直接求出,則觀察k的性質(zhì)。對于a[i]在所有n個數(shù)中的位置k,1---k-1中包括 less[i]個在 a[1] -- a[i-1]中的元素, //同時包括 t個在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已經(jīng)確定了他們在整個n個數(shù)中的位置(我們是從后往前進(jìn)行計算的), //則 1----k-1中就可以確定那t個元素的位置。//為了確定k的位置,則設(shè)置一個數(shù)組 b[1]--b[n],初始全部為0,從n到1統(tǒng)計,若a[i]的位置確定下來為p,則 b[p] = 1. //則對于任意的k,b[1]---b[k]中1的個數(shù)表示 1----k中被占用的位置,0 的位置表示未被占用的位置。//對于 a[i],找到某個k,使得其b[1]--b[k-1]中0的個數(shù)正好為 less[i]個,則k的位置就是 a[i]在整個n個數(shù)中的按照大小排序的位置//利用線段樹,找到 b[1]---b[pos]中 0的個數(shù)為k個的pos的位置 void FindKth(int k, int index, int& pos){if (gNodes[index].sum_zero < k){return;}if (gNodes[index].beg == gNodes[index].end){gNodes[index].sum_zero = 0;pos = gNodes[index].beg;return;}int left = 2 * index + 1, right = 2 * index + 2;gNodes[index].sum_zero--;if (gNodes[left].sum_zero >= k){FindKth(k, left, pos);}else{FindKth(k - gNodes[left].sum_zero, right, pos);} }int main(){int n;scanf("%d", &n);BuildTree(0, n - 1, 0);for (int i = 2; i <= n; i++){scanf("%d", &gLess[i]);}int pos = 0;gLess[1] = 0;for (int i = n; i >= 1; i--){FindKth(gLess[i] + 1, 0, pos);gPos[i] = pos + 1;}for (int i = 1; i <= n; i++){printf("%d\n", gPos[i]);}return 0; }?2.?樹狀數(shù)組
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<algorithm> #include<string.h> #define MAX_COW_NUM 80010 int gLowBit[MAX_COW_NUM]; int gC[MAX_COW_NUM]; int gLess[MAX_COW_NUM]; int gPos[MAX_COW_NUM]; bool gUsed[MAX_COW_NUM]; void InitLowBit(int n){for (int i = 1; i <= n; i++){gLowBit[i] = i&(-i);} } void InitSequence(int n){for (int i = 1; i <= n; i++){gC[i] = gLowBit[i];} }//樹狀數(shù)組的更新 void Update(int p, int n, int add){while (p <= n){gC[p] += add;p += gLowBit[p];} }//樹狀數(shù)組的查詢 int Query(int p){int result = 0;while (p > 0){result += gC[p];p -= gLowBit[p];}return result; }//二分法,查找滿足要求的 位置 int Search(int k, int n){int beg = 1, end = n + 1;while (beg < end){int mid = (beg + end) >> 1;int sum_zero = Query(mid);if (sum_zero == k){while (mid + 1 < end){ //用于判斷該位置是否被占用if (gUsed[mid + 1])mid++;elsebreak;}return mid + 1;}else if (sum_zero < k){beg = mid + 1;}else{end = mid;} }return 1; }int main(){int n;scanf("%d", &n);gLess[1] = 0;InitLowBit(n);InitSequence(n);memset(gUsed, false, sizeof(gUsed));for (int i = 2; i <= n; i++){scanf("%d", &gLess[i]);}for (int i = n; i >= 1; i--){int pos = Search(gLess[i], n);gPos[i] = pos;gUsed[pos] = true;Update(pos, n, -1);}for (int i = 1; i <= n; i++){printf("%d\n", gPos[i]);}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的poj_2182 线段树/树状数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈Android布局
- 下一篇: Vim 基本配置和经常使用的命令