Tido 习题-二叉树-树状数组求逆序对
Posted tidoblogs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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{ long long val,index; }; lisan a[100005]; long long C[100005]; int nn; int cmp1(lisan a,lisan b){ if(a.val==b.val)return a.index<b.index;//sort的不稳定性
//因为再下一次是按照下标再排回来,所以如果有数值相等的数,原来的下标先后顺序不能改变,否则会出现一些玄学错误 return a.val<b.val; } int cmp2(lisan a,lisan b){ return a.index<b.index; } int lowbit(int x){ return x&(-x); } void add(int x,int d){ while(x<=nn){ C[x]+=d; x+=lowbit(x); }//修改是从左往右 } long long sum(int x){ long long ret=0; while(x>0){ ret+=C[x]; x-=lowbit(x);//求和是从右往左 } return ret; } int main() { int n; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i].val; a[i].index=i; } //数据离散化模式开始 sort(a+1,a+n+1,cmp1); int x=0; for(int i=1;i<=n;i++){ if(a[i].val==a[i-1].val) a[i].val=x; else a[i].val=++x; } nn=x; sort(a+1,a+n+1,cmp2); //开始前缀和 long long ans=0; for(int i=n;i>=1;i--){ add(a[i].val,1); ans+=sum(a[i].val-1); } cout<<ans; return 0; }
思路讲解:
假如有8个数,
a:1 3 2 4 3 1 2 4
从后往前扫
设一个数组分别表示从后往前扫当前每个数值一共出现了几次
一开始是这样的,扫最后一个4
b:0 0 0 1
b[4]之前全是0,所以ans=0+0+0 这里的前缀和用树状数组就可以
再扫2
b:0 1 0 1 b[2]之前全是0
再扫1
b:1 1 0 1 b[1]之前还是0
再扫3
1 1 1 1 终于b[3]之前1+1=2意思也就是之前的两个1,代表已经扫过的1、2分别出现了一次
也就是说,在a数组中,a[5]后比3小的一共有两个
如此往下。。。。。
但是这一题每一个数的最大值是10的九次方,要是开数组的话就炸了
但是数的个数最多只有100000
所以可用数据离散化
先从小到大排序
都压成1,2,3.。。。
至于数据离散化是什么呢
就是比如原来有一组数1 2 45 67568684 3252 653357.
因为数据范围较大,但是数的个数却不是很大
但是如果有的数太大有的数太小
就会不是非常方便
这样如果用这个数的数值作为一个数组的下标,当然就方便多了
我们在使用的时候只看重数与数之间谁大谁小的关系
可以把上面的一行数缩成1 2 3 6 4 5
以上是关于Tido 习题-二叉树-树状数组求逆序对的主要内容,如果未能解决你的问题,请参考以下文章