首页 > 编程语言 >树状数组解决逆序对问题c++

树状数组解决逆序对问题c++

时间:2023-04-21 12:04:14浏览次数:36  
标签:树状 int sum c++ 查询 数组 逆序


前言

在算法竞赛中,求逆序对是一个常见的问题。逆序对是指在一个数列中,如果存在 树状数组解决逆序对问题c++_逆序对,且 树状数组解决逆序对问题c++_数据结构_02,那么 树状数组解决逆序对问题c++_排序算法_03 就是一个逆序对。例如,数列 树状数组解决逆序对问题c++_算法_04 中的逆序对有 树状数组解决逆序对问题c++_数据结构_05,总共有 树状数组解决逆序对问题c++_树状数组_06

树状数组

树状数组(Fenwick Tree)是一种高效的数据结构,用于维护数列的前缀和。树状数组的主要优势在于可以快速对数列进行单点更新和区间查询,时间复杂度均为 树状数组解决逆序对问题c++_算法_07。因此,可以使用树状数组来计算逆序对的个数。

树状数组求逆序对

假设有一个长度为 树状数组解决逆序对问题c++_数据结构_08 的数列 树状数组解决逆序对问题c++_数据结构_09,现在需要求解它的逆序对个数。可以使用树状数组来实现,具体步骤如下:

  1. 从后往前遍历数列 树状数组解决逆序对问题c++_逆序对_10,对于每个数 树状数组解决逆序对问题c++_排序算法_11,使用树状数组查询小于 树状数组解决逆序对问题c++_排序算法_11 的数的个数 树状数组解决逆序对问题c++_树状数组_13
  2. 树状数组解决逆序对问题c++_排序算法_11 加入树状数组,表示 树状数组解决逆序对问题c++_排序算法_11
  3. 由于 树状数组解决逆序对问题c++_排序算法_11树状数组解决逆序对问题c++_数据结构_17 都小,因此逆序对的个数可以加上 树状数组解决逆序对问题c++_树状数组_13,表示这些数与 树状数组解决逆序对问题c++_排序算法_11
  4. 重复步骤 树状数组解决逆序对问题c++_逆序对_20树状数组解决逆序对问题c++_数据结构_21,直到遍历完整个数列;
  5. 根据树状数组的结果计算逆序对的个数,并输出结果。 具体实现时,需要使用一个数组 树状数组解决逆序对问题c++_数据结构_22 存储树状数组,其中 树状数组解决逆序对问题c++_逆序对_23 表示第 树状数组解决逆序对问题c++_数据结构_24
c++Copy code// 更新树状数组
void update(int x, int v) {
    while (x <= n) {
        c[x] += v;
        x += lowbit(x);
    }
}
// 查询树状数组
int query(int x) {
    int res = 0;
    while (x > 0) {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

其中 lowbit(x) 表示 树状数组解决逆序对问题c++_数据结构_25 的二进制表示中最低位的 树状数组解决逆序对问题c++_排序算法_26 所对应的值,即 lowbit(x) = x & -x。 最终,根据树状数组的结果计算逆序对的个数,并输出结果。


过程演示:以 5 4 2 6 3 1数组为例,求它的逆序对:

  1. i=6,此时元素为1,首先查询比 1 小的元素的数量:query(0),sum=0;接着维护树状数组:update(1),c[1]=1,c[2]=1,c[4]=1,c[8]=1
  2. i=5,此时元素为3,首先查询比 3 小的元素的数量:query(2),查询到c[2]=1,sum+=c[2],sum=1;接着维护树状数组:update(3),c[3]=1,c[4]=2,c[8]=2
  3. i=4,此时元素为6,首先查询比 6 小的元素的数量:query(5),5可以分解为5和4,因此查询到c[4]=2,c[5]=0,sum+=c[4],sum=3;接着维护树状数组:update(6),c[6]=1,c[8]=3
  4. i=3,此时元素为2,首先查询比 2 小的元素的数量:query(1),因此查询到c[1]=1,sum+=c[1],sum=4;接着维护树状数组:update(2),c[2]=2,c[4]=3,c[8]=4
  5. i=2,此时元素为4,首先查询比 4 小的元素的数量:query(3),3可以分解为3和2,因此查询到c[3]=1,c[2]=2,sum+=c[3]+=c[2],sum=7;接着维护树状数组:update(4),c[4]=4,c[8]=5
  6. i=1,此时元素为5,首先查询比 5 小的元素的数量:query(4),因此查询到c[4]=4,sum+=c[4],sum=11;接着维护树状数组:update(2),c[2]=1,c[4]=3,c[8]=4

树状数组解决逆序对问题c++_排序算法_27

以下是完整的 C++ 代码实现:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, a[MAXN], c[MAXN];
// 计算 x 的 lowbit
inline int lowbit(int x) { return x & -x; }
// 更新树状数组
void update(int x, int v) {
    while (x <= n) {
        c[x] += v;
        x += lowbit(x);
    }
}
// 查询树状数组
int query(int x) {
    int res = 0;
    while (x > 0) {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}
int main() {
    // 读入数据
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    // 计算逆序对个数
    long long ans = 0;
    for (int i = n; i >= 1; i--) {
        ans += query(a[i] - 1);
        update(a[i], 1);
    }
    // 输出结果
    printf("%lld\n", ans);
    return 0;
}

总结

树状数组是一种高效的数据结构,用于维护数列的前缀和。使用树状数组可以高效地计算逆序对的个数。树状数组的核心思想是利用二进制的特性,通过计算每个数的 lowbit 来实现快速的更新和查询。希望本文能够对你有所帮助。


标签:树状,int,sum,c++,查询,数组,逆序
From: https://blog.51cto.com/u_15744744/6212424

相关文章

  • 二分查找例题与模板(蓝桥杯复习+例题讲解+模板c++)
    文章目录二分模板1460.我在哪?102.最佳牛围栏113.特殊排序二分模板本文所使用的二分模板都是确保最终答案落在[L,R]以内,循环以L==R结束,每次二分的中间值会使mid成为左右区间的二者之一。单调递增序列找大于等于x的最小的值:区间的划分[l,mid][mid+1,r]while(l<r){ intmid......
  • AC自动机的C++代码实现与过程讲解
    AC自动机(Aho-Corasickalgorithm)是一种多模式字符串匹配算法。它可以快速地查找多个模式串在一段文本串中出现的位置,并支持模式串的预处理,使得在查询时能够快速地匹配。C++代码实现:#include<iostream>#include<queue>#include<cstring>usingnamespacestd;constintM......
  • 网络流的C++代码实现与过程讲解
    网络流是一种非常重要的图论算法,它在许多实际问题中得到广泛应用。本文将介绍网络流算法的C++代码实现与过程讲解。算法概述网络流算法是通过将图中的边看作流量通道,将图的点看作流量的起点或终点,来求解图中的最大或最小流量的问题。它是一种非常重要的最优化算法,广泛应用于图论......
  • 初学者代码训练Day4(c/c++)
    题目:借书方案知多少小明有5本新书,要借给A、B、C这3位小朋友,若每人每次只能借1本,则可以有多少种不同的借法? 流程图  代码 #include<iostream>usingnamespacestd;intmain(){intA=0,B=0,C=0,sum=0;for(A=1;A<=5;A++){for(B=1;B<=5&&B!=A;B++)......
  • C++ 结构体对齐
    C++结构体对齐引言数据结构对齐是数据在计算机内存中排列和访问的方式。它由三个独立但相关的问题组成:数据对齐、数据结构填充和打包。现代计算机硬件中的CPU在数据自然对齐时最有效地执行内存读取和写入,这通常意味着数据的内存地址是数据大小的倍数。例如,在32位架构中,如果......
  • C++基础2: 优化C函数
    1.缺省参数什么是缺省参数缺省参数是声明或者定义函数时为函数的参数指定一个默认值,如果函数调用时没有传入实参,那么这个默认值会被当做实参,如下例子函数调用时,传入参数1,a=1,不传入参数,默认a=0,这里的a就是一个缺省参数缺省参数的分类缺省参数分全缺省和半缺省......
  • c++打卡第四天
    一、问题描述。有一对兔子,第三个月开始每月生一对兔子,刚出生的兔子经过三个月又可以生一对兔子,问从1月开始到n月,每月兔子的数量。二、设计思路。①、第一二个月都是一对兔子,第三个月是2对,3个月是三对,第四个月就是5对。②、由此可知,这个月兔子对数的总量等于前一个月和前两个月......
  • C/C++《程序设计基础(C语言)课程设计》[2023-04-20]
    C/C++《程序设计基础(C语言)课程设计》[2023-04-20]《程序设计基础(C语言)课程设计》课程说明及动员《程序设计基础(C语言)课程设计》指导教师组目录课程目的>>课程要求>>团队题目>>实施方案>>课程设计报告>>考核与成绩评定方法>>本学期实施安排>>其他说明课程目的......
  • C++课本第四章例题
    时钟类的完整例题#include<iostream>usingnamespacestd;classClock{private:inthour,minute,second;public:voidsetTime(inthour=0,intminute=0,intsecond=0);voidshowTime();};voidClock::setTime(intnewH,intnewM,i......
  • 构建树状结构工具类
    实体类@DatapublicclassTreeNode{/**节点ID*/privateIntegerid;/**父节点ID:顶级节点为0*/privateIntegerparentId;/**节点名称*/privateStringlabel;/**子节点*/privateList<TreeNode>children;/**......