CSU-ACM2017暑期訓練16-樹狀數組 H - Bubble Sort HDU - 5775

H - Bubble Sort

 P is a permutation of the integers from 1 to N(index starting from 1).
Here is the code of Bubble Sort in C++.


for(int i=1;i<=N;++i)
    for(int j=N,t;j>i;—j)
        if(P[j-1] > P[j])
            t=P[j],P[j]=P[j-1],P[j-1]=t;


After the sort, the array is in increasing order. ?? wants to know the absolute values of difference of rightmost place and leftmost place for every number it reached. 

Input

The first line of the input gives the number of test cases T; T test cases follow.
Each consists of one line with one integer N, followed by another line with a permutation of the integers from 1 to N, inclusive.

limits
T <= 20
1 <= N <= 100000
N is larger than 10000 in only one case.

Output

For each test case output “Case #x: y1 y2 … yN” (without quotes), where x is the test case number (starting from 1), and yi is the difference of rightmost place and leftmost place of number i.

Sample Input

2
3
3 1 2
3
1 2 3

Sample Output

Case #1: 1 1 2
Case #2: 0 0 0

Hint

In first case, (3, 1, 2) -> (3, 1, 2) -> (1, 3, 2) -> (1, 2, 3)
the leftmost place and rightmost place of 1 is 1 and 2, 2 is 2 and 3, 3 is 1 and 3
In second case, the array has already in increasing order. So the answer of every number is 0.

感覺又是一道難點主要在讀題上的題目。
題意爲:求出執行冒泡排序的過程中,數組中的每個數字所能到達的的最左位置與最右位置之間的距離。比方說 [3,1,2] 這個數組中,數字1最靠左時在位置1,最靠右時在位置2,故間距爲1;數字2最靠左時在位置2,最靠右時在位置3,故間距爲1;數字3最靠左時在位置1,最靠右時在位置3,故間距爲2。

由冒泡排序的性質可以知道,對某個數字而言,如果它所在的起始位置編號小於數字本身,如上例中的數字3,它最靠左時的位置就是它的起始位置;而若它所在的起始位置編號大於數字本身,如上例中的數字1,它最靠左時的位置就是它自身數值所述的位置。一個數字能有多靠右,則看數組中這個數字右側有幾個數小於它,如果有n個數小於它,則這個數字最靠右的位置就是它的起始位置右移n位。

有了上述標準,只需求出一個數字右側小於它的數字的數量,就能結合其起始位置算出答案。這個右側較小數字的數量通過樹狀數組得到。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 1e5 + 19;

int T, n;

int c[maxn], a, res[maxn];

void add(int x, int d) {
    while(x <= n) {
        c[x] += d;
        x += x & -x;
    }
}

int sum(int x) {
    int ret = 0;
    while(x > 0) {
        ret += c[x];
        x -= x & -x;
    }
    return ret;
}

int main() {
#ifdef TEST
    freopen("test.txt", "r", stdin);
#endif // TEST

    cin >> T;
    int cas = 1;
    while(T--) {
        cin >> n;
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a);
            res[a] = (a > i ? i : a);                // 確定最左位置。
            int afterSmaller = a - 1 - sum(a);       // 確定最大右移量。
            res[a] = abs(res[a] - afterSmaller - i); // 算出最左位置與最右位置的間距。
            add(a, 1);
        }
        printf("Case #%d: ", cas++);
        for(int i = 1; i <= n; i++)
            printf("%d%c", res[i], " \n"[i == n]);
    }

    return 0;
}
發佈了68 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章