标签:树状数组 end input namespace his 位置 str sorted get
Input
Output
Sample Input
5
9 1 0 5 4
3
1 2 3 0
Sample Output
6 0
给你一个排序,让你求出这个排序中的逆序数.算是自己写的树状数组的第一道题吧,这个题首先用到离散化思想.
因为每个数都是小于1e9,而n的范围不超过5e5,而且我们只关心这些数的大小关系,所以我们就把这些数全部映射到1~n,然后再按照排好序的位置插进去就行了
这样子是不会影响最后算逆序数的.映射后的序列为reflect
接下来求逆序数,这时要用到树状数组,树状数组的功能是用来求数组前缀和的,我们假想有一个长度为n的数组,它现在每一位初始化为0
我们按照位置顺序将reflect中的每一个数插入到树状数组中,假设我们现在插入的数是第i个数,它的值为x
那么我就把刚刚假想的数组的第x位置变为1,即代表x被插入到该序列
那么每一次对于ans怎样+呢?
我们可以定义sum(x) x及小于x的数中有多少个元素已经被插入
这样的话sum(x)就是我们刚刚那个假想数组的前缀和了,我们用树状数组可以求
对于插入的第i个数,我们的ans+=i-sum(x),因为x是第i个数插进来的,之前插进来小于等于x的数为sum(x)
两者做差就是在x之前插入,而且值要大于x的数字的个数
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const int maxn =550000; 7 int reflect[maxn]; 8 int c[maxn]; 9 int n; 10 int lowbit (int x) 11 { 12 return x&(-x); 13 } 14 struct Node 15 { 16 int val,pos; 17 }; 18 Node node[maxn]; 19 bool cmp (Node q1,Node q2) 20 { 21 return q1.val<q2.val; 22 } 23 24 void update (int x) 25 { 26 while (x<=n){ 27 c[x]+=1;//将我们想象的数组x位置附为1,直接就加到c[x]上了 28 x+=lowbit(x);//找父节点 29 } 30 } 31 int getsum (int x) 32 { 33 int sum=0; 34 while (x>0){ 35 sum+=c[x]; 36 /*求和时可以看作将x用二进制表示 37 temp=x; 38 每次加上c[temp],再把temp最后1位置上的值改成0 39 最后变成0时就求完了 40 如:求 101001 41 temp=101001 -> sum+=c[101001] 42 -> temp=101000 -> sum+=c[101000] 43 -> temp=100000 -> sum+=c[100000] 44 -> temp=000000 求完了 45 */ 46 x-=lowbit(x); 47 } 48 return sum; 49 } 50 int main() 51 { 52 //freopen("de.txt","r",stdin); 53 while (scanf("%d",&n)&&n){ 54 for (int i=1;i<=n;++i){ 55 scanf("%d",&node[i].val); 56 node[i].pos=i; 57 } 58 sort(node+1,node + n + 1, cmp); 59 for (int i=1;i<=n;++i) reflect[node[i].pos]=i;//离散化映射到1~n 60 for (int i=0;i<=n;++i) c[i]=0;//初始化树状数组 61 long long ans=0; 62 for (int i=1;i<=n;++i){ 63 update(reflect[i]);//插入一个数,更新一下 64 ans+=i-getsum(reflect[i]);//ans加一下 65 } 66 printf("%lld\n",ans); 67 } 68 return 0; 69 }
POJ 2299 Ultra-QuickSort (树状数组+离散化 求逆序数)
标签:树状数组 end input namespace his 位置 str sorted get
原文地址:http://www.cnblogs.com/agenthtb/p/6884099.html