树状数组求逆序对

逆序对的概念我就不讲了,关于这个求逆序对的问题,通俗的方法自然是要么遍历O(n^2),要么归并排序(nlog n ),那么如何用树状数组实现呢?

下面看一道题目

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2

其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

我将基于这题讲下去

首先通过数学证明加上离散化我们可以得到一个数组c[i],含义就是对于a火柴盒中的每一个位置i,在b中本该对应的位置(反过来也可以),那么问题就转化成了在c[i]数组中求逆序对的问题

下面我提供关键代码

void add(int x,int y){//添加

for(;x<=n;x+=x&-x)

    d[x]+=y;
}

int ask(int x){//询问前缀和

int y=0;

for(;x;x-=x&-x)

    y+=d[x];

return y;
}

for(int i=n;i>=1;i--){

add(c[i],1);

ans+=ask(c[i]-1);
}

最后输出ans就好了

问什么呢???

仔细分析一下

假设在ans+=ask(c[i]-1)之中,现在i=i0,有前缀可以给你加,那么这个前缀是怎么来的呢?

很显然,是通过第一步中来的.那么我们发现,由于i是从n递减,在c[i]中,一定有之前前缀和值个数位于现在的位置之前,并且它们在顺序的数组中的位置还要在c[i0]之前,也就是小于i0。因此我们只需要求前缀和就能知道逆序对的个数。

由此原理计算逆序对

星星之火,终将成燎原之势
原文地址:https://www.cnblogs.com/xxzh/p/9154068.html