题意是给出一个由1~n组成的序列,求出模拟冒泡排序时,每个数能到达的最左位置和最右位置的差。
暴力找下规律,会发现一个数右移的次数是右边比这个数小的数的个数,所以右边的位置是当前位置加上后面比这个数小的数的个数。左边位置是排完序后的位置与一开始所在的位置中更小的那个。求右边比这个数小的数的个数用树状数组,类似白书例题LA 4329的做法。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int C[maxn];
int n;
inline int lowbit(int x) {
return x & (-x);
}
int sum(int x) {
int ret = 0;
while(x > 0) {
ret += C[x]; x -= lowbit(x);
}
return ret;
}
void add(int x, int d) {
while(x <= maxn) {
C[x] += d; x += lowbit(x);
}
}
int a[maxn];
int r[maxn], l[maxn];
int id[maxn];
int main() {
int t;
scanf("%d", &t);
int cas = 0;
while(t--) {
memset(C, 0, sizeof(C));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = n; i >= 1; i--) {
add(a[i], 1);
r[i] = sum(a[i] - 1);
id[a[i]] = i;
}
//for(int i = 1; i <= n; i++) printf("%d ", r[i]); puts("");
vector<int> ans;
for(int i = 1; i <= n; i++) {
int ll = min(id[i], i);
int rr = id[i] + r[id[i]];
//printf("check %d %d %d\n", i, ll, rr);
ans.push_back(rr - ll);
}
printf("Case #%d:", ++cas);
for(int i = 0; i < ans.size(); i++) {
printf(" %d", ans[i]);
}puts("");
}
}