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 习题-二叉树-树状数组求逆序对的主要内容,如果未能解决你的问题,请参考以下文章

Tido 习题-二叉树-最高分

Tido 习题-二叉树-区间查询

树状数组求逆序对

树状数组求逆序对

树状数组求逆序对

HDU 1394 Minimum Inversion Number (树状数组求逆序对)