树状数组离散优化解决逆序对(洛谷P1908)

  该题数据已经被加强,而且出现hack数据,洛谷的部分用树状数组的题解可能有误,因此我这个新手蒟蒻想写一篇新的题解。

题目详情:

  https://www.luogu.com.cn/problem/P1908

不知道树状数组的童鞋请先移步。。。。(有关树状数组已经有苣佬讲的很清楚了,可以先看懂了再来)

有一组数,a1,a2,a3,an,逆序对的定义:如果i<j&&ai>aj的有序对。

1.很容易想到,把整个数组遍历一遍,用两个for循环,那么复杂度是o(n^2),对于题目中n的范围只能拿部分分。

2.归并排序(这里不多介绍了)蒟蒻只会数状数组

3.重头戏--树状数组+离散化

  以题目的样例来看

6

5 4 2 6 3 1

下标:、


 1 2 3 4 5 6

离散化操作

用b[n]数组储存每个数,a[n]数组储存下标

我们规定a[n]数组排序是b[n]数组大小来排的,也即是哪个b[n]大哪个a[n]排前面。

用c++的sort(...)(c++ stl yyds!)

这样得到a[n]

4 1 2 5 3 6

然后把a[n]放进树状数组,每放一次算一次sum。

这样做好处就是放入一个数时,后面那个数一定小于它,这个时候只需要比较下标就可以知道逆序对(我们已经按照数的大小排好了下标顺序),每次放入一个数,只需要把它的位置++就好,++就代表这个位置存在几个同一元素,接着计算sum(a[i]-1),也就是排在它前面的下标从0开始,到它的下标减一有多少个数(比较下标)。

ans+=sum(a[i]-1)

例如:

我们把4放入后,计算sum(3),发现是0,那么继续

1放入,计算sum(0),发现是0,继续

2放入,计算sum(1),发现是1,ans=1

5放入,计算sum(4),发现是3,ans=4

3放入,计算sum(2),发现是2,ans=6

6放入,计算sum(5),发现是5,ans=11

到此,答案就出来了,ans=11

那么这个问题基本就解决了。

细节问题

1.测试中可能会爆int,那么就用long long(不要问我怎么知道的,反正wa了一片的时候我还以为答案错了)

2.可能会出现同一个元素而且不同位置,解决办法:stable_sort(...)

接下来放代码qwq,树状数组模板

​
​
void add(long long x)
{
    while(x<=n)
    {
        c[x]++;     //对于每一个数,我们只需要让这个位置的值++就好因为我们最后会算sum
        x+=lowbit(x);
    }
}
bool cmp(const long long &x,const long long &y)
{
    return b[x]>=b[y];
}
long long sum(long long x)
{
    long long cnt=0;
    while(x>0)
    {
       cnt+=c[x];
       x-=lowbit(x);
    }
    return cnt;
}

​

​

没了。

你问我主函数去哪了,这个我这个蒟蒻没必要展示我的糟糕代码了

其实不想放。。。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值