BIT(树状数组)——求逆序对数
既然上次我写了一个归并排序求逆序对的方法,而且以前也写过一个BIT基础的教程,那么这次我们就来讲一下逆序对的另一种求法——使用BIT求解逆序对数。
逆序对是这样定义的:如果i < j 并且ai > aj 那么这就叫一个逆序对。不难看出,其实我们可以用离散化的方法来做。但是离散化后,就一定要使用BIT去求解了。
我们的BIT的基础函数还是不变的,但是要操作别的东西达到我们求解逆序对数的目的:
1 首先对于将数字离散化,这个我们是需要用到排序的,我们需要使用数字的大小来记录这个数本来在第几位,以及这个数在求逆序对之前应该在第几位,那我们就要用到algorithm库中的sort函数(Pascal只能手写函数,对此我表示我很同情学P的同学们),相信大家也应该会使用struct,所以呢,这里附上代码,毕竟代码才是真理。
1 struct edge{ 2 int v,pos; 3 }in[100010]; // 定义 4 bool cmp(edge a,edge b){ 5 return a.v < b.v; 6 } 7 8 for(int i = 1;i <= n;++i){ 9 cin >> in[i].v; 10 in[i].pos = i; 11 } 12 sort(in+1,in+n+1,cmp);
2. 对于离散化后的数据(按照顺序保存),我们要对其进行操作,加装一个新的数组(按位置保存的数组),然后算每个数据在整个数据中应该排第几位(注意,题目有可能出现ai = aj,所以要手工计算,而不能排完序就一撒手,然后记录下来原先在哪个位置的数据现在在那个位置,需要重新进行循环计算,看看这个数据到底在哪个位置上);
3.以上操作完成以后,我们的记录工作便完成了,接下来就是使用BIT来计算了:执行从1到n的循环,对于每一个aa[i]执行加一操作,不记录在aa数组中,只在c数组中进行计算,然后接着ans要加上i-query(aa[i])(这是关于原先第i位的数的逆序对的个数,query(aa[i])是指在i之前比a小的数的个数,此处比较难懂,请读者自己想一想,因为我也是说不清楚到底过程是怎样的,但是我个人认为还是自己思考的要好一些),之后累加在一个ANS变量中,ANS最终就是我们所求的逆序对数
现在我们来说一下这个算法的时间复杂度上的问题,事实上这个代码的时间复杂度和归并排序求逆序对数是相同的都是O(nlogn)。因为每次BIT的基本操作的时间复杂度都是O(logn),然后我们在主程序中循环求解中循环了n次,所以时间复杂度就相当于O(nlogn),这个代码比较好写,但是就是很难懂,如果大家习惯了归并排序求逆序对的操作后,这个方法我建议涉猎一下,但是还是不要写自己拿不稳的程序,以免程序出错。
代码才是真理,一切嘴上说的都是空虚的,附上代码——(建议大家先背代码,然后再去逐步理解,毕竟代码很难懂,我自己都想了1个月左右才刚刚有点理解):
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #define lowbit(x) x&-x 5 using namespace std; 6 int n; 7 long long ans; 8 int c[100010]; 9 struct edge{ 10 int v,pos; 11 }in[100010]; 12 bool cmp(edge a,edge b){ 13 return a.v < b.v; 14 } 15 long long aa[100010]; 16 int query(int x){ 17 long long ret = 0; 18 while(x > 0){ 19 ret += c[x]; 20 x -= lowbit(x); 21 } 22 return ret; 23 } 24 void add(int x,int d){ 25 while(x <= n){ 26 c[x] += d; 27 x += lowbit(x); 28 } 29 } 30 int main(){ 31 cin >> n; 32 ans = 0; 33 memset(aa,0,sizeof(aa)); 34 memset(c,0,sizeof(c)); 35 for(int i = 1;i <= n;++i){ 36 cin >> in[i].v; 37 in[i].pos = i; 38 } 39 sort(in+1,in+n+1,cmp); 40 int reflect = 0; 41 for(int i = 1;i <= n;++i){ 42 if(in[i].v != in[i-1].v)reflect++; 43 aa[in[i].pos] = reflect; 44 } 45 for(int i = 1;i <= n;++i){ 46 add(aa[i],1); 47 ans += i - query(aa[i]); 48 } 49 cout << ans << endl; 50 return 0; 51 }

浙公网安备 33010602011771号