求逆序对 ----归并排 & 树状数组
网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的
好了下面是正文
- 归并排求逆序对
- 树状数组求逆序对
一、归并排求逆序对
–
温馨提示:阅读这段内容需要的知识点:归并排序
— 首先的话,归并排序大家应该都知道的吧?归并排是利用分治的思想,先分后和,分到左右区间相等或相交时在返回上一层进行两个有序小数组交错插入排序,形成一个有序数组,然后层层返回排好序的数组,作为新的小数组插入大数组排序,这就是一个n log n的排序算法(带 log 的算法一般都算是比较快的,只要常数不过大)。然后还是不懂的同学可以百度,这里不细讲了。另外提一提,实在是不会用归并排的话冒泡也是一样可以求逆序对的,累加的话就变成了判断到需要交换时进行,但冒泡的复杂度高了点,是 n^2 了,提交 后会爆几个点就不知道了,得看具体题目和数据。(反正数据一般不会水到让你满分【斜眼笑ing】)
— 其次的话,用归并排求逆序对无非也就是在插入的过程中将 逆序数 ans 累加,然后也没什么不同的了,只要记得归并排模板的话基本也是码的出来的。(个人感觉归并排求逆序队还是挺清晰的,因为这样基本就是套套模板不用想太多)
模板如下,但请别直接复制粘贴,好歹自己打一遍
int n,ans;
const int mod=;
int f[],g[]; void merge_sort(int l,int r)
{
if(l>=r) //如果说l、r交错的话直接return不管
return ; int mid=(l+r)>>; //以l、r的中点为界向下分支排序
merge_sort(l,mid);
merge_sort(mid+,r); int i=l,j=mid+,k=l;
while(i<=mid && j<=r) //保证两个小的数组不超边界
{
if(f[i]<f[j])
g[k++]=f[i++];
else
{ //大概要在模板上做修改的就是这块了,用ans把逆序对累加
ans=(ans+mid-i+)%mod; //如果题目中有取余就%mod
g[k++]=f[j++];
}
}
// 然后把剩下的数直接插入到大的数组末尾(但不会对ans进行累加操作)
while(i<=mid)
g[k++]=f[i++];
while(j<=r)
g[k++]=f[j++];
for(int i=l;i<=r;++i) //g数组只是一个中间量,用完就丢了,f才是要排序的数组
f[i]=g[i]; }
二次分析
–然后我觉得还得解释一下为什么ans在j数组(即第二个小数组)中的值插入到达数组的时候才累加。试想,逆序对就是大的数字在前面,小的数字在后面,每次发现一组这样的数字对那么整个数组中的逆序对数量就可以+1了。
如:1 2 6 8 和 3 5 7 9 ,初始i指向1,j指向3,k指向8,l指向9,ans=0
在第一次比较时,1<3,则1插入进大数组,i++,ans不变
第二次比较式,i指向了2, 2<3,则2插入进大数组,还是i++,ans不变
第三次,i指向6,6>3,3入大数组,j++,ans+=2 。
这里就是重点了,3小于6,则3也一定小于6后面的数,并且可以和这些数(共两个)分别对应形成n个逆序对(n为k-i+1,即6和6的后面总共还剩多少个数)
第四次也一样,是j++,ans+=2,此时ans为4,原理同上,不再解释
然后就是继续向大数组队尾插入数了,我们发现直到 i 数组为空时(全被插入完毕了),j 数组仍有剩余,那么就将 j 数组直接插入进大数组,但ans不进行累加(因为此时 i 数组空了,无法与 j 数组中剩下的数形成逆序对)
呼~这样总该解释的差不多了,同志们自个儿好好消化消化吧。
二、树状数组求逆序对
–
温馨提示:阅读本段需要具备的知识点:树状数组的基本操作(update、getsum、lowbit之类的)
–首先的话,树状数组我也不来说这么详细了,许多细节方面(如 getsum 时x为什么要减去一个lowbit(x)了之类的)的理解就麻烦请自己思考得出或是去问百度了。
–其次的话,树状数组其实就是代码短一点(短一点就好码一点,好码一点就好调试一点,好调试一点就不容易出错一点),看着舒服吧。
然后我就不啰嗦了,直接上代码吧。
int lowbit(int x) //lowbit求最末尾的1所在的位置
{
return x&(-x);
} void update(int x,int k) //update等会儿讲
{
for(;x<=n;x+=lowbit(x))
g[x]+=k;
} long long getsum(int x) //getsum的话。。。也等会儿讲
{
long long res=;
for(;x;x-=lowbit(x)) //一直跳向比x小的数,如7->6->4->0(结束)
//或是6->4->0(结束)
res+=g[x];
return res;
} void BIT() //这个BIT啊,我看书的时候也不知道是什么鬼,
//然后才发现原来是树状数组英文名(Binary Indexed Trees)的缩写
{
for(int i=;i<=n;++i)
{
update(f[i],);
ans=(ans+f[i]-getsum(f[i]))%mod;
}
}
另外提一点,不要看着这个代码好像行数很多,码一遍之后会发现真的很短
然后讲讲update和getsum吧(主要是给学过的人讲,谈谈我的理解)
上图!
在这里的话,你可以认为每个三角形的顶端都是一个BOSS,一旦他们的下属出现了之后,下属会先+1,再逐级向上汇报(也就是说有小三角形的话就先向小三角形上的BOSS先汇报,然后再由这个小的BOSS向更大的BOSS汇报,直到顶层), 这样的话我们最后就可以清晰地得到一个实时更新的树状数组,每个g中所存的就是它以及它的下属目前已出现的个数
这里的话 6 在getsum的时候路径为6->4->0(结束),得到的 res 为 1,即已出现的数字中,小于等于6的数字只有一个
那么上面演示的是有逆序对的情况,同样的,你也可以自行演示一下 先 2 后 6的情况,这时候你会发现 ans 并没有累加,即没有逆序对的情况……
总之,还是要熟知树状数组操作里的含义吧。
好了,心血来潮写的一篇博客终于搞定了。(大概花了两个多小时的样子,是不是蒟蒻?)
然后如果说有哪里我讲的不对的话,欢迎各位 神(da)犇(lao)在评论区里喷我。_ (:зゝ∠) _
bye bye(下次见)!
1000010 1011001 1000101————!(一串ASCII码)
求逆序对 ----归并排 & 树状数组的更多相关文章
- codevs 4163 求逆序对的数目 -树状数组法
4163 hzwer与逆序对 时间限制: 10 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description hzwer在研究逆序对. 对于数列{a},如果 ...
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...
- 51 Nod 1107 斜率小于0的连线数量 (转换为归并求逆序数或者直接树状数组,超级详细题解!!!)
1107 斜率小于0的连线数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 二维平面上N个点之间共有C(n,2)条连线.求这C(n,2)条线中斜率小于0的线 ...
- bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)
3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...
- 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)
2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...
- 求逆序对常用的两种算法 ----归并排 & 树状数组
网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的 好了下面是正文 归并排求逆序对 树状数组求逆序对 一. ...
- hdu 1394 Minimum Inversion Number(逆序数对) : 树状数组 O(nlogn)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 //hdu 题目 Problem Description The inversion number ...
- Dynamic Inversions II 逆序数的性质 树状数组求逆序数
Dynamic Inversions II Time Limit: 6000/3000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Other ...
- 用归并排序或树状数组求逆序对数量 poj2299
题目链接:https://vjudge.net/problem/POJ-2299 推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/ ...
随机推荐
- android studio导出apk
在android studio导出的apk分为4种,一种是未签名调试版apk,一种是未签名发行版apk,一种是已签名调试版apk,还有一种是已签名发行版apk.以下将介绍这4种apk如何导出. 一.调 ...
- 原生JavaScript运动功能系列(三):多物体多值运动
多物体同时出发运动函数实现 多属性同步运动变化实现 一.多物同时触发运动函数实现 前面两个动画示例基本理解了动画的核心:位置变化和速度变化,操作的核心就是定时器分段叠加属性值.但是动画还是基于单个元素 ...
- 理解maven命令package、install、deploy的联系与区别
我们在用maven构建java项目时,最常用的打包命令有mvn package.mvn install.deploy,这三个命令都可完成打jar包或war(当然也可以是其它形式的包)的功能,但这三个命 ...
- 转---redshift database ---学习
摘自他人 前沿 根据最近一段时间对redshift的研究,发现一些特性比较适合我们当前的业务. 1 比如它的快速恢复能力,因为这一点,我们可以尽量在redshit里面存放一定生命周期的数据,对过期的数 ...
- javascript&&jquery编写插件模板
javascrpt插件编写模板 这里不分享如何编写插件,只留一个框架模板,使用面向对象的形式进行编写,方便管理 ;(function(window,document){ function FnName ...
- DataReader分页性能测试
参考程序地址:http://www.cnblogs.com/eaglet/archive/2008/10/09/1306806.html 最近遇见程序慢的问题,使用的DataReader,猜想是分页导 ...
- Jquery触发Change事件
Jquery直接使用val的话不会触发Change事件需要做如下处理$("#"+p_id).val(p_time); $("#"+p_id).change();
- 机器学习等知识--- map/reduce, python 读json数据。。。
map/ reduce 了解: 简单介绍map/reduce 模式: http://www.csdn.net/article/2013-01-07/2813477-confused-about-map ...
- cocos2dx 动画控制概要
-------------------------------------------------Cocos2d 播放动画Node : 节点,所有显示容器的基础 Sprite : 使用图片的节点 An ...
- codeforces706E
好精妙的一道题啊 传送门:here 大致题意:有一个$ n*m$的矩阵,q次询问每次交换给定两个无交矩阵的对应元素,求操作后的最终矩阵? 数据范围:$ n,m<=1000, q<=1000 ...