当前位置: 首页 > news >正文

树状数组+离散化求逆序对超详细讲解!

树状数组+离散化求逆序对

用一个数组 w [ ] w[] w[]来记录遍历到当前数时,每个数出现的次数
由于只关心每个数前边有多少个数比他大,遍历到 i i i时,求大于 a [ i ] a[i] a[i]的数有多少个,就是对 [ a [ i ] , n ] [a[i], n] [a[i],n]求和。
之后将 a [ i ] a[i] a[i]的出现次数 w [ a [ i ] ] + 1 w[a[i]]+1 w[a[i]]+1再求后边的答案。

如果暴力来做是 O ( n 2 ) O(n^2) O(n2)的(不知道这个对不对,不过不重要)

for (int i = 1; i <= n; i++) {int cnt = 0;for (int j = a[i]; j <= n; j++) {cnt += w[j];}ans += cnt;w[a[i]]++;
}

发现即要做单点修改 w [ a [ i ] ] + 1 w[a[i]] + 1 w[a[i]]+1,又要做区间查询 ∑ j = a [ i ] n w [ j ] \sum\limits_{j=a[i]}^{n} w[j] j=a[i]nw[j],于是用树状数组维护 w [ ] w[] w[]来降低复杂度。

回顾树状数组的两个操作:区间查询 + 单点修改
q u e r y ( i ) 表示查询区间 [ 1 , i ] 的和 query(i)表示查询区间[1, i]的和 query(i)表示查询区间[1,i]的和
a d d ( i , k ) 表示将含有 a [ i ] 的点都 + k add(i, k)表示将含有a[i]的点都+k add(i,k)表示将含有a[i]的点都+k

(实际上这里说的树状数组是权值树状数组,就是记录每个数出现的次数的树状数组)

一个前提:只关心相对大小,数本身有多大我并不关心,所以可以离散化(否则数据太大的话 w [ ] w[] w[]放不下那么大的下标会爆掉)

写法1

按照每个数的大小降序排序,如果大小相等则按照位置降序排序(考虑为什么这么做?)

假设在排序后的数组中第 i i i个数的原位置为 p [ i ] p[i] p[i]树状数组维护的是,每个原位置的数是否出现。
比如:

原数组:3 2 1 5 4
下标 :1 2 3 4 5排序后:5 4 3 2 1
原位置:4 5 1 2 3遍历到第2个数4时,记录情况为:[0, 0, 0, 1, 0],即原位置为4的数已经出现了。
我们知道4的原位置为5,此时对区间[1, 5]求和,就是原位置5对应的逆序对数量。
把原位置5记录进去。遍历到第3个数3时,记录情况为:[0, 0, 0, 1, 1],原位置4 5的数已经出现了
知道3的原位置为1,此时对区间[1, 1]求和,就是原位置1对应逆序对的数量。
把原位置1记录进去。遍历到第4个数2时,记录情况为:[1, 0, 0, 1, 1],原位置1 4 5的数已经出现了
知道2的原位置为2,此时对区间[1, 2]求和,就是原位置2对应逆序对的数量。
把原位置2记录进去。遍历到第5个数1时,记录情况为:[1, 1, 0, 1, 1],原位置1 2 4 5的数已经出现了
知道1的原位置为3,此时对区间[1, 3]求和,就是原位置3对应逆序对的数量。
把原位置3记录进去。

看懂这一丁点就行,下边是一顿胡扯,可以不看了


注意:以下所有情况都在排好序的数组中进行!!!

现在来考虑两个情况

1. 当前数是唯一的,不考虑相同数位置降序排序的情况

记第 i 个数为 a [ i ] , 排序前位置为 p [ i ] 记第i个数为a[i], 排序前位置为p[i] 记第i个数为a[i],排序前位置为p[i]
要查询这个位置对应的逆序对数量
因为我们已经按照降序进行了排序,就变为查询 位置在 p [ i ] p[i] p[i]之前且大于 a [ i ] a[i] a[i]的数的个数
对应到排序后的数组中就是:
  前 i − 1 i - 1 i1个数中原位置在 p [ i ] p[i] p[i]之前的数。
  因为排序已经确保了前 i − 1 i - 1 i1个数都是比 a [ i ] a[i] a[i]大的数,现在只需要在前 i − 1 i - 1 i1个数中找到位置在 p [ i ] p[i] p[i]前的数就可以了

比他大的数在排序前只有两种情况:在他前边/在他后边
只有 (排序前在他前边) 的数才会构成逆序对,在他后边的数不会构成逆序对

再次强调,因为是降序排序,故已经确保了 (遍历到第 i i i个数时已经记录出现的数) 都是大于 a [ i ] a[i] a[i]的。

那么对于第 i i i个数,(比 a [ i ] a[i] a[i]大) 且 (在 p [ i ] p[i] p[i]之前出现) 的数的个数,实际上就是已经记录出现了的数的个数,即 [ 1 , p [ i ] ] [1, p[i]] [1,p[i]]的和。求区间 [ 1 , p [ i ] ] [1, p[i]] [1,p[i]]的和,就是 q u e r y ( p [ i ] ) query(p[i]) query(p[i])
最后将这个位置的数记为出现, a d d ( p [ i ] , 1 ) add(p[i], 1) add(p[i],1)

2. 如果数不唯一

数不唯一的话按照位置降序排序

考虑一下,假设已经按照位置进行了降序排序
当前数为 a [ i ] a[i] a[i],位置 p [ i ] p[i] p[i]
排序后数组中在当前数之前的相同数 a [ j ] a[j] a[j],对应位置 p [ j ] p[j] p[j]一定在 p [ i ] p[i] p[i]后边
那么 [ 1 , p [ i ] ] [1, p[i]] [1,p[i]]求和时,是这样的一个区间:
1 2 3 4 ... p[i] ... p[j] ...
就不会把相同的数也算到逆序对中,这样就避免了重复计算。

总结一下核心:降序排序后每个位置 i i i要查询的区间和 [ 1 , p [ i ] ] [1,p[i]] [1,p[i]],是出现在原数组位置 p [ i ] p[i] p[i]之前且大于当前数的元素个数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>#define debug(x) std::cerr << "#x" << " = " << x << ' '
#define DEBUG(x) std::cerr << "#x" << " = " << x << std::endltypedef long long ll;
using namespace std;const int N_MAX = 500000 + 10;int n;
int tr[N_MAX];
struct Node {int v, p;bool operator < (const Node& other) const {if (v != other.v) return v > other.v;return p > other.p;}
}a[N_MAX];int lowbit(int x) {return x & -x;
}void inc(int x, int v) {for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;
}ll calc(int x) {ll sum = 0ll;for (int i = x; i >= 1; i -= lowbit(i)) sum += tr[i];return sum;
}int main() {cin >> n;for (int i = 1; i <= n; i++) cin >> a[i].v, a[i].p = i;sort(a + 1, a + n + 1);ll ans = 0ll;for (int i = 1; i <= n; i++) {ans += calc(a[i].p);inc(a[i].p, 1);}printf("%lld\n", ans);return 0;
}

相关文章:

树状数组+离散化求逆序对超详细讲解!

树状数组离散化求逆序对 用一个数组 w [ ] w[] w[]来记录遍历到当前数时&#xff0c;每个数出现的次数 由于只关心每个数前边有多少个数比他大&#xff0c;遍历到 i i i时&#xff0c;求大于 a [ i ] a[i] a[i]的数有多少个&#xff0c;就是对 [ a [ i ] , n ] [a[i], n] [a[i…...

《解密云计算:企业之选》

前言 在当今数字化时代&#xff0c;企业面临着巨大的数据处理压力和信息化需求&#xff0c;传统的IT架构已经无法满足日益增长的业务需求。在这样的背景下&#xff0c;越来越多的企业开始转向云计算&#xff0c;以实现灵活、高效和可扩展的IT资源管理和利用。 云计算 云计算是…...

地址分词 | EXCEL批量进行地址分词,标准化为十一级地址

一 需求 物流需要对用户输入地址进行检查&#xff0c;受用户录入习惯地址可能存在多种问题。 地址标准化是基于地址引擎和地址大数据模型&#xff0c;自动将地址信息标准化为省、市、区市县、街镇、小区、楼栋、单元、楼层、房屋、房间等元素&#xff0c;补充层级缺失数据、构建…...

KubeSphere平台安装系列之二【Linux单节点部署KubeSphere】(2/3)

**《KubeSphere平台安装系列》** 【Kubernetes上安装KubeSphere&#xff08;亲测–实操完整版&#xff09;】&#xff08;1/3&#xff09; 【Linux单节点部署KubeSphere】&#xff08;2/3&#xff09; 【Linux多节点部署KubeSphere】&#xff08;3/3&#xff09; **《KubeS…...

网络安全: Kali Linux 使用 docker-compose 部署 openvas

目录 一、实验 1.环境 2.Kali Linux 安装docker与docker-compose 3.Kali Linux 使用docker-compose方式部署 openvas 4. KaliLinux 使用openvas 二、问题 1. 信息安全漏洞库 2.信息安全漏洞共享平台 3.Windows 更新指南与查询 4.CVE 查询 5.docker-compose 如何修改o…...

【学习考试心得】在誉天学习考试RHCE9.0的体验

作为华中第一位参加RHCE9.0线上考试的考生&#xff0c;很荣幸能来写这个心得&#xff0c;和大家分享一下线上的考试的一些体验。 一、学习体验 首先在红帽课程的学习中&#xff0c;跟着杨峰老师的脚步&#xff0c;整个学习过程中都非常有意思。杨峰老师充满磁性的声音和小王老师…...

Flip Clock(not good)

最近体验了一下iOS的翻页时钟app&#xff0c;很想自己做一个&#xff0c;但是效果不好 public class main {public static void main(String[] args) {//psvmnew MyFrame();} }import javax.swing.*; import java.awt.*; import java.io.File; import java.io.IOException; im…...

目标检测——摩托车头盔检测数据集

一、简介 首先&#xff0c;摩托车作为一种交通工具&#xff0c;具有高速、开放和稳定性差的特点&#xff0c;其事故发生率高&#xff0c;伤亡率排在机动车辆损伤的首位。因此&#xff0c;摩托车乘员头盔对于保护驾乘人员头部安全至关重要。在驾乘突发状况、人体受冲击时&#…...

Windows 安装 Xinference

Windows 安装 Xinference 0. 引言1. 创建虚拟环境2. 安装 pytorch3. 安装 llama_cpp_python4. 安装 chatglm-cpp5. 安装 Xinference6. 设置 model 路径7. 启动 Xinference8. 查看 Cluster Information 0. 引言 Xorbits Inference&#xff08;Xinference&#xff09;是一个性能…...

静态时序分析:SDC约束命令set_case_analysis详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 目录 指定值 指定端口/引脚列表 简单使用 set_case_analysis命令用于对电路进行特定模式的设定&#xff0c;例如对于一个工作在正常模式下的芯片&#xff0c;…...

C++ · 代码笔记4 ·继承与派生

目录 前言010继承与派生简单例程020多级继承030使用using关键词更改访问权限040隐藏050派生类与基类成员函数同名时不构成重载060使用多级继承展示成员变量在内存中的分布情况071派生类在函数头调用基类构造函数072构造函数调用顺序080构造函数与析构函数的调用顺序091多重继承…...

解决uni-app中使用webview键盘弹起遮挡input输入框问题

这个平平无奇的回答&#xff0c;可能是全网最靠谱的解决方案。 这里我用的是vue3 setup .vue文件的方式 <view> <web-view :fullscreen"false" :webview-styles"{top: statusBarHeight40,height:height,progress: {color: green,height:1px } }"…...

Java注解介绍

Java注解 注解介绍元注解RetentionTargetDocumentedInherited接口类测试结果 注解介绍 Java注解&#xff08;Annotation&#xff09;是一种元数据&#xff08;Metadata&#xff09;的形式&#xff0c;它可以被添加到Java代码中的类、方法、变量、参数等元素上&#xff0c;以提…...

万字详解,Java实现低配版线程池

文章目录 1.什么是线程池2.线程池的优势3.原理4.代码编写4.1 阻塞队列4.2 ThreadPool线程池4.3 Worker工作线程4.4 代码测试 5. 拒绝策略5.1 抽象Reject接口5.2 BlockingQueue新增tryPut方法5.3 修改ThreadPool的execute方法5.4 ThreadPool线程池构造函数修改5.5 拒绝策略实现1…...

挂耳式蓝牙耳机哪家的好用?购买耳机前必须了解的几大要点

随着健康意识的提升&#xff0c;越来越多的人开始热衷于运动。运动不仅能够增强体质&#xff0c;对于我们这些忙碌的上班族而言&#xff0c;它也是一种极佳的减压方式。经过一天的辛勤工作&#xff0c;能够在户外跑步&#xff0c;让汗水带走压力&#xff0c;实在是一种享受。在…...

CSS文本属性

CSS文本属性 1.文本颜色2.文本间距3. 文本修饰4 .文本缩进5.文本对齐_水平6.行高7. vertical-align 1.文本颜色 属性名&#xff1a;color作用&#xff1a;控制文字的颜色。可选值&#xff1a; 颜色名rgb或rgbaHEX或HEXA &#xff08;十六进制&#xff09;HSL或HSLA 开发中常用…...

MySQL篇—执行计划之覆盖索引Using index和条件过滤Using where介绍(第三篇,总共三篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…...

最短路径(2.19)

目录 1.网络延迟时间 弗洛伊德算法 迪杰斯特拉算法 2. K 站中转内最便宜的航班 3.从第一个节点出发到最后一个节点的受限路径数 4.到达目的地的方案数 1.网络延迟时间 有 n 个网络节点&#xff0c;标记为 1 到 n。 给你一个列表 times&#xff0c;表示信号经过 有向 边的…...

vue 总结

1.vue 的生命周期 1. es6 2. vue 基本属性指令 <template><div><!--<h1>vue基本指令的使用方式</h1><a :href"url">v-bind使用链接</a><img :src"srcUrl" /><div>解决闪烁问题<p v-cloak>{{…...

深入理解TCP/IP协议:互联网通信的核心

深入理解TCP/IP协议&#xff1a;互联网通信的核心 在数字化时代&#xff0c;TCP/IP协议是支撑全球互联网通信的基石。它不仅负责数据的传输和路由&#xff0c;还确保了信息传递的准确性和完整性。本文将深入探讨TCP/IP协议的工作原理、结构以及它在网络编程中的应用。 TCP/IP…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...