数状数组求逆序对

逆序对在很多地方用的到。以前都是用归并排序或线段树求,在《mato的文件管理》看到有人用树状数组求,很简单!整理如下:

思路:

首先,开一个大小为这些数的最大值的数组,作为树状数组。

然后,将各个数按顺序依次加入该数组。方法为:这个数大小对应的它在线段树中的位置,对这个位置上的数加1,并更新树状数组。所以当前树状数组中存着所有原数字序列中当前数前面的数,而getsum(i)就是 i 前面小于等于 i 的数的个数。i-getsum(i)-1也就是大于它的个数。这就是逆序对了。

  把每一个的逆序对数加起来就是答案了。

问题:

  数值太大。

  离散化。树状数组内不存数本身而是存它的排序。

代码:

 1 #include<bits/stdc++.h>
 2
 3 using namespace std;
 4 const int maxn=1e6+7;
 5 int n;
 6 int sz[maxn],c[maxn];
 7 struct node
 8 {
 9     int dat,pos;
10 }nd[maxn];
11
12 bool cmp(node a,node b)
13 {
14     return a.dat<b.dat;
15 }
16 inline int lowbit(int x)
17 {
18     return x&(-x);
19 }
20 int getsum(int x)
21 {
22     int sum=0;
23     for(;x>0;x-=lowbit(x))sum+=c[x];
24     return sum;
25 }
26 void updat(int x)
27 {
28     for(;x<=n;x+=lowbit(x))c[x]++;
29 }
30 int main()
31 {
32     cin>>n;
33     for(int i=1;i<=n;i++)
34     {
35         scanf("%d",sz+i);
36         nd[i].dat=sz[i];nd[i].pos=i;
37     }
38     sort(nd+1,nd+1+n,cmp);
39     int js=1;
40     sz[nd[1].pos]=1;
41     for(int i=2;i<=n;i++)
42     {
43         if(nd[i].dat==nd[i-1].dat)sz[nd[i].pos]=js;
44         else sz[nd[i].pos]=++js;
45     }
46     long long ans=0;
47     for(int i=1;i<=n;i++)
48     {
49         ans+=i-getsum(sz[i])-1;//<=sz[i]
50         updat(sz[i]);
51     }
52     cout<<ans;
53     return 0;
54 }

时间: 2024-10-01 06:19:07

数状数组求逆序对的相关文章

【bzoj2789】[Poi2012]Letters 树状数组求逆序对

题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. 输出 一个非负整数,表示最少的交换次数. 样例输入 3 ABC BCA 样例输出 2 题解 树状数组求逆序对 一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中

Day2:T4用树状数组求逆序对

T4: 用树状数组求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I B[J]>=B[I] 之后就是求逆序对的事情了 然后这里学一下用树状数组的方法 原理是:树状数组是用来求区间和的是吧 就是按权值的区间统计那么可以BIT维护...然后扫一遍 也就是计算有多少个逆序对 按权值的区间统计就是记录数的个数

蓝桥杯小朋友排队(树状数组求逆序对)

居然存在身高为0的数据... 树状数组求逆序对原理: add(h[j],1); //将身高为h[j]的数据的出现次数加1 sum(h[j]);//求i<j 且 h[i] <=h[j] 的数据出现次数之和  那么 i-sum(h[j]) 为 i > j 且 h[i] > h[j] 数据的出现次数之和 即为 逆序对数 #include"cstdio" #include"cstring" #define lowbit(i) i&(-i) u

树状数组求逆序对

给定n个数,要求这些数构成的逆序对的个数.除了用归并排序来求逆序对个数,还可以使用树状数组来求解.树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了.把所有的加起来就是总的逆序对数.题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

树状数组求逆序对:POJ 2299、3067

前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换相邻的两数使它有序,要你求出交换的次数.实质上就是求逆序对,网上有很多人说它的原理是冒泡排序,可以用归并排序来求出,但我一时间想不出它是如何和归并排序搭上边的(当初排序没学好啊~),只好用刚学过的树状数组来解决了.在POJ 1990中学到了如何在实际中应用上树状数组,没错,就是用个特殊的数组来记录即

hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792 题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值. 解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和

hdu5147 Sequence II树状数组求逆序对

//用树状数组求出在b前面比b小的数的个数 //然后求b后面的顺序对的个数, //枚举b可得quad //由于数列是从1到n的所有数 //那么(n-num[j])-(j-1-totol[j])即为第j个数之后比j大的数的个数 //其中num[j]表示第j个数,total[j]表示在j之前比j小的数的个数 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int

loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分

$ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinobu 早有准备,Alice.Ayaya.Karen.Shinobu.Yoko 五人又能继续愉快地玩耍啦! 「噢--!不是有放上天的烟花嘛!」Karen 兴奋地喊道. 「啊等等--」Yoko 惊呼.Karen 手持点燃引信的烟花,「嗯??」 Yoko 最希望见到的是排列优美的烟火,当然不会放过这个机会-

Tido 习题-二叉树-树状数组求逆序对

这里给大家提供一个全新的求逆序对的方法 是通过树状数组来实现的 题目描述   样例输入 Copy 5 2 3 1 5 4 样例输出 Copy 3 提示    #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<string> #include<cstring> using namespace std; struct lisan