题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5775
题意:给出一个1~n的排列,在给定的冒泡排序之后,问对于每个元素,它到达的最右和最左的位置的差值是多少。
思考:对于某一位数字,最右位置是max(i, a[i]),即初始位置或最终位置,最左位置为向左移动的次数,即比它小但在它右边的数的个数。那么问题的关键就转移到了逆序数,树状数组求解即可。总复杂度
O(nlogn)
。
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cstring>
const int MAXN = 100000 + 10;
int a[MAXN], c[MAXN], ans[MAXN];
int n;
inline int lowbit(int x){
return x & (-x);
}
void add(int pos, int p){
for(int i = pos; i <= n; i += lowbit(i)){
c[i] += p;
}
return;
}
int query(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= lowbit(pos);
}
return sum;
}
int main(int argc, char const *argv[]){
int cas;
int k = 1;
scanf("%d", &cas);
while(cas--){
scanf("%d", &n);
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; i++){
scanf("%d", a + i);
}
int l, r;
for(int i = 1; i <= n; i++){
add(a[i], 1);
r = std::max(i, a[i]);
l = query(a[i] - 1) + 1;
//printf("%d %d\n", l, r);
ans[a[i]] = abs(r - l);
}
printf("Case #%d: ", k++);
for(int i = 1; i <= n; ++i){
printf(i == n ? "%d\n" : "%d ", ans[i]);
}
}
return 0;
}