树状数组求逆序对

逆序对之树状数组 [树状数组]逆序对题目题目解析算法简介树状数组代码实现 题目 题目解析 逆序对可以用归并排序和树状数组: 归并排序就不用讲了,我们来讲讲树状数组 算法简介 树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log⁡2n\log_2{n}log2​n的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log⁡2n\log_2{n}log2​n的复杂度下进行范围修改。 这种数据结构 阅读详情

一般来说,求逆序对,方法如下:
1、如果 N<10000,可以用冒泡排序,交换次数就是逆序对数量,时间复杂度 O(n2),空间复杂度 O(n)
2、如果 N>=10000,用归并排序,是分治思想,时间复杂度 O(nlog2n),空间复杂度 O(2*n),见上面参考代码。
3、如果 K 表示最大元素和最小元素的差值,当 N 大于400000,K=50000 的时候,树状数组比分治更快,时间复杂度 O(nlog2K),空间复杂度 O(K)。

树状数组求逆序对的方法,在考场上不失一个好的选择,因为它不仅速度更快,而且代码也比较简单,因为我们是以数的大小为下标,所以情况可以分为两种,
第一种为题目给的需要求逆序对的数列的最大值太大,如果直接作为下标会浪费大量的空间,这时候需要离散化点值,使它缩小到我们可控的范围之内;
第二种则是数列大小恰好在N的范围内,即a[]max<=N,可以直接计算;

我们巧妙地运用了巧妙的树状数组,其中树状数组里面的a[](原数组)的下标表示的就是A序列里面的元素。例如:当A={3,3,1,9,11},循环时依次在a[3],a[3],a[1],a[9],a[11]加一。聪明的读者应该知道这个方法怎样实现了。没错,就是先读入元素ai,再将a[i]加一,然后用树状数组的特点在O(log2K)的时间复杂度求出Σa[k](1<=k<=i)。这样对于之前读入而且小于等于ai的元素个数为Σa[k],读入的ai为第i个元素,所以在ai前面且比ai大的元素为i-Σa[k],问题得以解决。

我们来看一道例题:

Prince对他在这片大陆上维护的秩序感到满意,于是决定启程离开艾泽拉斯。在他动身之前,Prince决定赋予King_Bette最强大的能量以守护世界、保卫这里的平衡与和谐。在那个时代,平衡是个梦想。因为有很多奇异的物种拥有各种不稳定的能量,平衡瞬间即被打破。KB决定求助于你,帮助他完成这个梦想。 一串数列即表示一个世界的状态。
平衡是指这串数列以升序排列,而从一串无序数列到有序数列需要通过交换数列中的元素来实现。KB的能量只能交换相邻两个数字。他想知道他最少需要交换几次就能使数列有序。
输入格式
第一行为数列中数的个数 N(n≤100000)。
第二行为 N 个数 a1~an (每个数小于100000),表示当前数列的状态。
输出格式
输出一个整数,表示最少需要交换几次能达到平衡状态。
这道题的题意就是求数列a中的逆序对的个数,我们注意到,“a1~an (每个数小于100000)”,所以这道题也就不需要离散化,可以直接求

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<string>
#include<cctype>
#include<set>
#include<queue>
using namespace std;
long long  n,x,tree[100005],ans; //不用long long 会在最后一个点溢出 
//---------------------
inline int lowbite(int i)
{
    return i & (-i);
}
//---------------------
inline void Update(int i,long long t)
{
    while(i<=n)//体会一下为什么我们用a[]做下标,却是i<=N
    {
       tree[i]+=t;
       i+=lowbite(i);
    }
}
//---------------------
inline int query(long long i)
{
    long long  tmp=0;
    while(i>0)
    {
        tmp+=tree[i];
        i-=lowbite(i);
    }
    return tmp;
}
//---------------------
int main()
{
    freopen("dream.in","r",stdin);

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        Update(x,1);
        ans+=(i-query(x));
    }
    cout<<ans;
    return 0;
}

代码中的问题就是因为“a1~an (每个数小于100000)”,所以就可以直接i<=n,否则就需要离散化。

POJ2299就是需要离散化得情况,离散化得过程如下:

 离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围,必要的是建立一个结构体a[n],v表示输入的值,order表示原i值,再用一个数组aa[n]存储离散化后的值  
 例如: 
 i:1 2 3 4 5 
 v: 9 0 1 5 4 
 排序后:0 1 4 5 9 
 order:2 3 5 4 1 如果建立映射:aa[a[i].order]=i; 
 aa:5 1 2 4 3 
 即原本的9经过排序应该在第5位,现在aa[1]=5,对应原来的9,大小次序不变,只是将9缩小到了5

其余过程大体同上,在此就不赘述。

树状数组——求逆序对个数(初学者都能看懂) 在网上翻看了一些博客,感觉大体对于树状数组求逆序对的讲解不够详细,那些博客,更多像是给已经学会逆序对的人复习用的。而初学者,可能要冥思苦想。接下来,我便从一个初学者的角度,来一步步的,讲解一下由树状数组求逆序对。需要的前置知识只有,会线段数组的基本应用。单点更新,区间查询,求lowbit。 先贴树状数组的基本代码。 求lowbit int lowbit(x){return x&(-x);} 单点更新 void update(int x,int y,int n){ for(int i=x;i 阅读详情

相关推荐

RK3588平台-ES8388音频驱动调试与设备树配置实战

本文详细解析了在RK3588平台上调试ES8388音频驱动的实战过程。内容涵盖Linux音频驱动的三层架构(Machine、Platform、Codec),并重点提供了设备树(DTS)的完整配置示例,包括I2C节点、声卡节点及音频路由设置。文章还分享了驱动加载验证、amixer调试命令以及常见问题(如无声、变调)的排查思路,旨在帮助开发者快速完成RK3588与ES8388的音频系统集成。

mango的博客 806

树状数组之求逆序对

树状数组之求逆序对 逆序对    设 A 为一个有 n 个数字的有序集 (n>1), 其中所有数字各不相同。 如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A [i] > A [j], 则 <A [i], A [j]> 这个有序对称为 A 的一个逆 序对,也称作逆序数。 例如,数组 (3,1,4,5,2) 的逆序对有 (3,1),(3,2),(4,2),(5,2), 共 4 个。 原理 我们有以下的设定 a[]={0,3,1,4,5,2} 其中 3,1,

DC_Fan的博客 2463

自制《大侠狂想曲》修改器:内存修改、加速与一键安装全攻略

游戏修改器是玩家优化游戏体验的常用工具,其核心原理是通过内存修改技术,在游戏进程运行时动态改写数值。常见实现路径是借助Cheat Engine扫描并追踪数据地址,再通过编程语言调用系统API完成读写。这种技术能有效解决重复刷资源带来的枯燥感,特别适用于单机RPG中想快速体验多剧情线却不想重刷资源的情形。本文以《大侠狂想曲》为例,完整拆解了从CE定位金钱与好感度内存地址,到编写C#脚本实现游戏加速、一键增加铜钱与NPC好感度,再到用Inno Setup打包生成一键安装器的全过程,并总结了数值弹回、剧情不触发、

weixin_30368981的博客 1459

树状数组(求逆序对)

一、树状数组是什么 树状数组,又称二进制索引树,英文名Binary Indexed Tree 之前遇到一个求逆序对的题,看了很多题解都只说了这个树状数组,关于怎么实现的全都避而不谈,我研究了一下午,总算搞出个头绪了 一般用来求前缀和,可以把时间复杂度从O(n)降到O(log10 n)非常恐怖,举个例子,假如我们要求从1~1000的前缀和,普通方法需要遍历1000次,而树状数组只需要遍历5次,...

卑鄙的我 2万+

吃透 AM32 无人机电调:从源码架构到工作原理的全方位解析(附实践指南)(上)

本文深入解析了AM32电调固件的源码架构与核心模块实现。文章首先介绍了AM32电调作为开源无人机;动力心脏的重要地位,随后从硬件基础、源码目录、模块划分三个维度构建解析框架。重点剖析了系统初始化模块的时钟配置、GPIO初始化和定时器设置,以及FOC控制模块的坐标变换算法、角度估算和SVPWM生成等关键技术实现。通过逐行代码解析,揭示了电调如何将飞控指令转换为电机驱动的完整过程,为开发者理解AM32电调工作原理提供了系统性指导。

bother3000的博客 6554

claude使用教程

提供了三种模型:claude,codex, gemini,三种模型都共用同一个apikey, 有开发需求使用claude效果较好,知识问答等场景gemini效果会更好些,本文只提供了claude的安装方式,剩下两种按需按照以下参考链接安装下即可,安装有问题参考文档:https://www.aicodemirror.com/dashboard/official-installation/macos-linux (不需要挂梯子,自己手机号注册就好)

lichao19871216的博客 3468

树状数组简单总结(原理见以往帖子)

树状数组:快速(动态)求前缀和 在线算法(支持修改) O(logn) 1:给某个位置上的数加上一个增量(修改某个元素) 2:求某个前缀和 即:单点修改,区间查询(sum(r)-sum(l-1)) 树状数组只能支持这俩问题,别的问题都得通过转化才能解决 比如区间修改,单点查询 需要利用差分转化为区间修改 记树状数组为C[x],定义: C[x]=(x-lowbit[x],x],即x-lowbit[x]+1~x,奇数为其本身 lowbit[x]=x&-x,含义是2^k,k为x...

明月千里赴迢遥的博客 681

若依(RuoYi)框架从零到部署:Spring Boot+Vue权限系统完整配置指南

在Java企业级应用开发中,Spring Boot作为构建微服务和单体应用的基石,极大地简化了项目初始化和配置流程。其核心原理在于通过自动配置和起步依赖,快速整合数据访问、安全认证、缓存等常用模块,显著提升开发效率。这一技术价值在需要快速构建后台管理系统的场景中尤为突出,例如权限管理、用户角色分配等通用需求。若依(RuoYi)框架正是基于Spring Boot和Vue.js的优秀实践,它封装了RBAC权限模型、代码生成器等高频功能,提供了开箱即用的解决方案。本文聚焦于若依框架的【环境配置】与【项目部署】,通

weixin_33984032的博客 455

超详细笔记:树状数组求解逆序对数

纯纯蒟蒻看不懂各位大佬的题解,搜集了各路大佬的思考方式,做出一些小总结,关于整个思考过程,怎么想到离散化,怎么想到树状数组的过程,而不只是给出解法,大佬轻喷,文章仅供和我一样不太理解的萌新们找找感觉,因为详细所以十分啰嗦,才能保证看得懂,请见谅。题目原意:对于给定的一段正整数序列,逆序对就是序列中 ai​>aj​ 且 i<j 的有序对,求长度为n的序列的逆序对数总数。(n在50W以内,时间复杂度必须在 nlogn 内)这里不做线段树解法和归并排序的解法(大佬们都讲的很清楚了)仅考虑树状数组。

Island_0801的博客 4310

从零构建物联网数据中台:MQTT协议、Node.js服务、MongoDB与InfluxDB双存储及React可视化实战

本文详细介绍了从零构建物联网数据中台的完整实战方案。通过采用MQTT协议作为设备通信标准,结合Node.js搭建高并发数据处理服务,并创新性地使用MongoDB与InfluxDB双存储架构分别管理设备元数据与海量时序数据,最后利用React构建了实时数据可视化控制台。该架构有效解决了物联网项目中数据异构、查询性能低下等核心痛点,为构建高效、可扩展的物联网平台提供了清晰路径。

weixin_28432777的博客 288

DeepSeek网页版和DeepSeek Harness

DeepSeek网页版是开箱即用的对话工具,适合快速问答与日常任务;而DeepSeekHarness(dsh)是基于Node.js的开源智能体框架,支持文件操作、命令执行、多工具协同,实现“对话即执行”。二者定位不同:网页版为“大脑”,Harness为“躯体”。前者封闭易用,后者开放可扩展,具备可追溯的执行日志与插件化架构。未来,网页版将聚焦轻量化普及,Harness则致力于构建生态平台。对开发者而言,应将AI作为执行层,守住决策层,深耕垂直领域,并掌握AI工作流设计能力,以构建不可替代的技术优势。

几十年资深高级架构师,技术专家的技术笔记。专注C、Java、Python、微服务、云原生、AI工程化及高并发系统分布式架构实战,分享源码剖析、性能调优与架构治理经验。 859

树状数组+求逆序对

右图圆圈中标记有数字的结点,存储的是称为树状数组的tree[]tree[]。一个结点上的tree[]tree[]的值,就是它树下的直连的子结点的和。例如: tree[1]=a1​ tree[2]=tree[1]+a2​ tree[3]=a3​ tree[4]=tree[2]+tree[3]+a4​ ⋯ tree[8]=tree[4]+tree[6]+tree[7]+a8​ 而我们利用tree[],有效地完成下面两个操作: 查询,即求前缀和sum,例如: sum(8)=tre...

weixin_62355410的博客 2762

Kafka 性能优化与常见问题排查

Kafka 的高性能依赖于合理的集群设计、参数优化与高效的监控体系。生产环境中,应重点关注I/O 瓶颈、分区规划、Producer/Consumer 参数调优,并通过监控与排查手段快速定位问题,从而保障 Kafka 在实时场景下的稳定运行。

X2829352498的博客 234

【树状数组 求逆序对】排序

首先需要了解逆序对是什么:逆序对就是如果i &gt; j &amp;&amp; a[i] &lt; a[j],这两个就算一对逆序对。其实也就是对于每个数而言,找找排在其前面有多少个比自己大的数。那么思路就来了,树状数组又一次地优化了这种“需要遍历”的情况。那不就很容易了吗?依次把序列里的数放到树状数组中的A[i]上去(实际是以C[i]形式的插入函数),注意A[i]是以数值大小从小到大排列的。先插入...

It's the Climb 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

树状数组离散化求逆序对(模板)

考虑根据值来建树状数组 , 初始树状数组为全0。现在按照序列从左到右将数据的值对应的位置的数加一,代表又有一个数出现。因此,在循环到第项时,前项已经加入到树状数组内了 , 树状数组内比大的都会与构成逆序对,因为它们一定出现的更早,所以产生的逆序对数量为(表示当前比小的个数,为总的个数,相减就是前面,比大的个数了,也就是当前数的逆序对)。当然也可以直接用来求。 #...

sugarbliss 683

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

洛谷 P4378 —— 树状数组求逆序对

除了朴素求逆序对,常见的求逆序对主要有两种方法。

Miserable_ccf的博客 849

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

利用树状数组求逆序对

逆序对: ai>aj 且 i<j 。说白了就是一个序列中前面比后面大的对,举个例子: 序列2 1 4 3 2 , (2 1)就是一个逆序对,(4 3)、(4 2)也是。 暴力做法: 遍历这个序列,数一下每个元素前面比他大的元素的个数,累加就是最后的结果,举个例子: 序列2 1 4 3 2 第一个元素 2,前面没有元素,结果 = 0 第二个元素 1,前面比他大的是 2,结果 = 1 第三个元素 4,前面没有比他大的,结果 = 0 第四个元素 3,前面比他大的是 4,结果 = 1 第五个元素 2

weixin_45743427的博客 352

Tido 习题-二叉树-树状数组求逆序对

这里给大家提供一个全新的求逆序对的方法 是通过树状数组来实现的 题目描述 样例输入Copy 5 2 3 1 5 4 样例输出 Copy 3 提示 #include<iostream> #include<cstdio> #include<...

weixin_34410662的博客 425

树状数组求逆序对 poj2299

树状数组求逆序对; 对于一组任意顺序的数,记下他们的初位置,再进行排序,记下他们本来应该在的位置。然后,按最初位置从前往后,进行处理。 基本思想: 对于一个数要求它对应得逆序对,可以通过求前面小于等于它的数的个数,然后用当前已处理的数的个数-前面小于等于当前的数的个数得到。 如: 4 3 5 2 1 排序后 1 2 3 4 5 对于第一个数4,当前处理数的个数为1,本来应该在的位置是4,则在第4个...

weixin_43184669的博客 206

[树状数组]求逆序对

树状数组基本讲解: 树状数组的用途就是求前缀和,他的本质跟线段树相似,就是一个空间换时间。 主要采用lowbit,通过二进制从而划分区间。 增加的时候,从下往上依次加lowbit 查询的时候,从上往下减去lowbit。 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdl...

weixin_30561177的博客 111
上一篇: 2017.4.22NOIP2017模拟考试总结
下一篇: 一些解题过程中关于数据范围的细节
Amessal
博客等级 码龄10年 9粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值