【求助帖】| 树状数组求逆序对

在这里插入图片描述

#include <bits/stdc++.h>
#define read(x) scanf("%d",&x)
#define lowbit(x) ((x)&(-x))
using namespace std;

typedef long long ll;
const int N=1e5+10;
struct node {
    int h,idx;
    bool operator < (const node  &b) const {
        if (h!=b.h) return h<b.h; //身高升序排列,求下标的逆序对
        else return idx<b.idx;
    }
}a[N];
int tr[N],w[N],n;//w数组存储每个位置的数的逆序对的个数

void update(int x,int c) {
  for (int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}

int query(int x) {
  int res=0;
  for (int i=x;i>=1;i-=lowbit(i)) res+=tr[i];
  return res;
}

ll getSum(int n) {
  return (ll)n*(n+1)/2;
}

int main()
{
    read(n);
    int h;
    for (int i=1;i<=n;i++) read(h),a[i]={h,i};
    
    //排序,
    sort(a+1,a+n+1);     
   //去重              
    for (int i=2;i<=n;i++) 
      if (a[i].h==a[i-1].h) a[i].idx=a[i-1].idx;
      
    //a[i]主动和谁换?求左边比a[i]大的
    for (int i=1;i<=n;i++) {
        update(a[i].idx,1);
        w[i]=i-query(a[i].idx);  
    }
    
    //a[i]被谁换?求右边比a[i]小的
    memset(tr,0,sizeof tr);
    for (int i=n;i>=1;i--) {
        update(a[i].idx,1);
        w[i]+=query(a[i].idx-1);
    }
    
    ll res=0;
    for (int i=1;i<=n;i++) res+=getSum(w[i]);
    printf("%lld",res);
    
    return 0;
}

但只能过两组数据,第三组数据就错了,不知道错哪了。哪天再回来看吧。

输入数据。

100
42 701 893 20 333 520 919 446 482 203 126 707 527 814 528 598 369 165 449 3 377 539 301 638 912 970 810 
102 149 983 713 410 472 89 382 785 142 824 73 141 199 825 317 679 219 597 548 67 343 467 566 580 924 337 
859 939 482 618 8 746 598 926 124 753 230 271 132 308 881 171 727 294 49 921 375 3 780 504 389 251 117
609 359 720 487 70 632 632 355 617 719 589 482 771 118 7 655 422 63 757

出错区间:

52
482 203 126 707 527 814 528 598 369 165 449 3 377 539 301 638 912 970 810 102 
149 983 713 410 472 89 382 785 142 824 73 141 199 825 317 679 219 597 548 67 
343 467 566 580 924 337 859 939 482 618 8 746 

2021.03.24

问题解决了,把第40、41行的去重去掉就好了。

结论:

离散化处理时,

  1. 如果求左边比它大的个数,右边比它小的个数:按h升序排列,如果h相同,则按idx升序排列。
  2. 如果求右边比它大的个数,左边比它小的个数:按h升序排列,如果h相同,则按idx降序排列。

不能去重,下标置相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值