题意,有一个1~n的排列,用冒泡法排序,问整个过程中每个数字能达到的最左最右的位置绝对值之差。
思路:
每个数能达到的最左位置不是开始位置就是排序完成后所在位置,所以L[ a[i] ] = min ( i , a[i] ),
每个数能达到的最右位置为开始位置,或i+num,num为a[i]后小于a[i]的数字个数。那么num[i]怎么求呢?利用树状数组,
在输入第i个数后,sum[ a[i] ]表示a[i]之前小于等于a[i]的个数,而小于等于a[i]的个数一定有a[i]个,所以num=a[i]-sum[ a[i] ].
R[ a[i] ]= max ( i + a[i] - sum ( a[i] ) , a[i] );
太菜了,理了半天才理清。。
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<sstream>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
int t,n;
int a[100006];
int bit[100006];
int R[100006];
int L[100006];
void add(int i,int x){
while(i<=n){
bit[i]+=x;
i+=i&-i;
}
}
int sum(int i){
int s=0;
while(i>0){
s+=bit[i];
i-=i&-i;
}
return s;
}
int main(){
freopen("in.txt","r",stdin);
cin>>t;
for(int ca=1;ca<=t;ca++){
printf("Case #%d:",ca);
cin>>n;
memset(bit,0,sizeof(bit));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
L[a[i]]=min(i,a[i]);
add(a[i],1);
R[a[i]]=max(i+a[i]-sum(a[i]),a[i]);
}
for(int i=1;i<=n;i++){
printf(" %d",abs(L[i]-R[i]));
}
printf("\n");
}
}