当前位置:   article > 正文

【HDU5775】 Bubble Sort 多校 树状数组 统计数组中某个数右边小于这个数的个数详解_树状数组 求右边比自己小的数的数量 c++

树状数组 求右边比自己小的数的数量 c++

Bubble Sort

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2605    Accepted Submission(s): 1255

Problem Description

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

  1. for(int i=1;i<=N;++i)
  2. for(int j=N,t;j>i;—j)
  3. if(P[j-1] > P[j])
  4. t=P[j],P[j]=P[j-1],P[j-1]=t;
  5. 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

  1. 2
  2. 3
  3. 3 1 2
  4. 3
  5. 1 2 3

 

Sample Output

  1. Case #1: 1 1 2
  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.

题意:就是有一个数组要进行冒泡排序,某个数在冒泡排序中出现在最左边的位置和最右边的位置之差的最大值。

题解:我们先分析一下这个数在最左边的位置,只有两种情况,一是它自己本身在数据中的那个位置,二是它本来在上升序列中应该出现的位置,最小的那个值就是它出现在最左边的那个位置。最右边的位置是它本身在数据中的位置+右边比他小的数的个数,为什么是小的数的个数呢,读者不妨想一下,因为冒泡排序把小的那个数往前移,所以某个数右边比他小的个数的每一个都会移到这个数的前面,所以这个数会向后移的距离为比他小的数的个数。所以通式为 ans=i+d-min(i,a[i]-1)。现在要解决的问题是怎么计算某个数右边的比他小的个数,树状数组,可以用来计数。要是读者懂树状数组的话,我们可以想一下,比如我们要统计某个数右边小于他的个数,我们将数逆序插入树状数组就看当前在这个数之前插入树状数组的数比这个小的数的个数,这个不难想到。因为最后一个数肯定右边没有比他更小的数,这时树状数组就是空的。我们就实时逆序插入,我们每插入一个数,就看在树状数组中这个数位置的前面有多少个数,因为比他小的数一定会插到这个数的前面,所以我们直接将权值赋值为1,通过求和就能知道这个数前面有多少个数,也就说在数组中这个数的右边有多少个比这个数小的数的个数。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<algorithm>
  5. using namespace std;
  6. const int maxn=100000+7;
  7. int a[maxn];
  8. int b[maxn];
  9. int tree[maxn<<1];
  10. int T,n;
  11. int lowbit(int x)
  12. {
  13. return x&-x;
  14. }
  15. int add(int x,int v) //更新结点
  16. {
  17. while(x<=n){
  18. tree[x]+=v;
  19. x+=lowbit(x);
  20. }
  21. return 0;
  22. }
  23. int getsum(int x) //求和
  24. {
  25. int ans=0;
  26. while(x>0){
  27. ans+=tree[x];
  28. x-=lowbit(x);
  29. }
  30. return ans;
  31. }
  32. int main()
  33. {
  34. scanf("%d",&T);
  35. for(int t=1;t<=T;t++){
  36. memset(tree,0,sizeof(tree));
  37. scanf("%d",&n);
  38. for(int i=0;i<n;i++){
  39. scanf("%d",&a[i]);
  40. }
  41. for(int i=n-1;i>=0;i--){ //因为最右边的那个数的后面不可能有比它还小的数
  42. int x=getsum(a[i]); //计算a[i]右边比a[i]小的元素的个数
  43. //因为它统计的是在这个数前面有多少个数 即比他小而且又提前插入
  44. add(a[i],1); //出现了a[i]就在a[i]对应的位置+1代表这个数出现一次
  45. b[a[i]]=i+x-min(i,a[i]-1); //i+x:数据中的位置+右边比这个数小的个数
  46. } //右边的比这个数小的个数就是它要往后移动的距离
  47. //min(i,a[i]-1) 最左边的话 要么它数组中的位置最左 要么它正确对应的位置最左
  48. printf("Case #%d: ",t);
  49. for(int i=1;i<=n;i++){
  50. if(i==1)printf("%d",b[i]);
  51. else printf(" %d",b[i]);
  52. }
  53. printf("\n");
  54. }
  55. return 0;
  56. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/227658
推荐阅读
相关标签
  

闽ICP备14008679号