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

原文地址:https://www.cnblogs.com/Tidoblogs/p/10887694.html

时间: 2024-08-01 19:20:54

Tido 习题-二叉树-树状数组求逆序对的相关文章

【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.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

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和

hdu1394Minimum Inversion Number树状数组求逆序对水题

//ans[i]=ans[i-1]+(n+1)-2*num[i] //num[i]为输入时的数据 //ans[i]为m=i时的逆序数 //用树状数组求ans[0]的逆序对 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=5010; int num[maxn]; int tree[maxn]; int lowbit(int i) { retu

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

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题目让你求一个数组,这个数组可以不断把最前面的元素移到最后,让你求其中某个数组中的逆序对最小是多少. 一开始就求原来初始数组的逆序对,树状数组求或者归并方法求(可以看<挑战程序设计>P178),然后根据最前面的元素大小递推一下每次移到最后得到的逆序数,取最小值. 1 #include <iostream> 2 #include <cstdio> 3 #include

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

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