网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的
好了下面是正文


  1. 归并排求逆序对
  2. 树状数组求逆序对

一、归并排求逆序对

温馨提示:阅读这段内容需要的知识点:归并排序

— 首先的话,归并排序大家应该都知道的吧?归并排是利用分治的思想,先分后和,分到左右区间相等或相交时在返回上一层进行两个有序小数组交错插入排序,形成一个有序数组,然后层层返回排好序的数组,作为新的小数组插入大数组排序,这就是一个n log n的排序算法(带 log 的算法一般都算是比较快的,只要常数不过大)。然后还是不懂的同学可以百度,这里不细讲了。另外提一提,实在是不会用归并排的话冒泡也是一样可以求逆序对的,累加的话就变成了判断到需要交换时进行,但冒泡的复杂度高了点,是 n^2 了,提交 后会爆几个点就不知道了,得看具体题目和数据。(反正数据一般不会水到让你满分【斜眼笑ing】)

— 其次的话,用归并排求逆序对无非也就是在插入的过程中将 逆序数 ans 累加,然后也没什么不同的了,只要记得归并排模板的话基本也是码的出来的。(个人感觉归并排求逆序队还是挺清晰的,因为这样基本就是套套模板不用想太多)

模板如下,但请别直接复制粘贴,好歹自己打一遍


int n,ans;
const int mod=99999997;
int f[100005],g[100005]; void merge_sort(int l,int r)
{
if(l>=r) //如果说l、r交错的话直接return不管
return ; int mid=(l+r)>>1; //以l、r的中点为界向下分支排序
merge_sort(l,mid);
merge_sort(mid+1,r); int i=l,j=mid+1,k=l;
while(i<=mid && j<=r) //保证两个小的数组不超边界
{
if(f[i]<f[j])
g[k++]=f[i++];
else
{ //大概要在模板上做修改的就是这块了,用ans把逆序对累加
ans=(ans+mid-i+1)%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=0;
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=1;i<=n;++i)
{
update(f[i],1);
ans=(ans+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码)

求逆序对常用的两种算法 ----归并排 & 树状数组的更多相关文章

  1. Ultra-QuickSort (求逆序数+离散化处理)、Cows、Stars【树状数组】

    一.Ultra-QuickSort(树状数组求逆序数) 题目链接(点击) Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total ...

  2. 求逆序对 ----归并排 & 树状数组

    网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的 好了下面是正文 归并排求逆序对 树状数组求逆序对 一. ...

  3. 算法进阶 (LIS变形) 固定长度截取求最长不下降子序列【动态规划】【树状数组】

    先学习下LIS最长上升子序列 ​ 看了大佬的文章OTZ:最长上升子序列 (LIS) 详解+例题模板 (全),其中包含普通O(n)算法*和以LIS长度及末尾元素成立数组的普通O(nlogn)算法,当然还 ...

  4. 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[]=A[]-M*( ...

  5. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  6. hdu2838 cow sorting用树状数组求逆序对

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/2838/ 题目解法:题目给出一个1-n的排列,操作只有一种:交换相邻的元素,代价是两个元素之和,问将该序列变成升序 ...

  7. codeforces 540E 离散化技巧+线段树/树状数组求逆序对

    传送门:https://codeforces.com/contest/540/problem/E 题意: 有一段无限长的序列,有n次交换,每次将u位置的元素和v位置的元素交换,问n次交换后这个序列的逆 ...

  8. 树状数组 && 线段树应用 -- 求逆序数

    参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...

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

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number                         ...

随机推荐

  1. 《通过C#学Proto.Actor模型》之 HelloWorld

    在微服务中,数据最终一致性的一个解决方案是通过有状态的Actor模型来达到,那什么是Actor模型呢? Actor是并行的计算模型,包含状态,行为,并且包含一个邮箱,来异步处理消息. 关于Actor的 ...

  2. 第十一节,利用yolov3训练自己的数据集

    1.环境配置 tensorflow1.12.0 Opencv3.4.2 keras pycharm 2.配置yolov3 下载yolov3代码:https://github.com/qqwweee/k ...

  3. Web Storage和cookie

    Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生; Web Storage的概念和cookie相似,区别是它是为了更大容 ...

  4. js模块化世界

    前言 我们经常见到 一些这样的写法,require('xxx').import xx from '../components/data'.export const data....也听见一些这样的说法 ...

  5. AtCoder Beginner Contest 124 D - Handstand(思维+前缀和)

    D - Handstand Time Limit: 2 sec / Memory Limit: 1024 MB Score : 400400 points Problem Statement NN p ...

  6. 软工+C(1): 题目设计、点评和评分

    // 下一篇:分数和checklist 如何设计题目 教学中的一个问题是老师出题太简单了,题目设计一开始上来就不紧凑,我认为一个好的课程应该上来就给你紧凑感,而不是先上来"轻松2-3周&qu ...

  7. 2019微信公开课 同行With Us 听课笔记及演讲全文

    [2019WeChat 微信公开课] 产品理念: 微信启动页 一个小人站在地球前面,每个人都有自己的理解和解读 所谓异类,表示与别人与众不同,即优秀的代名词. 微信的与众不同体现在尊重用户对产品的感受 ...

  8. CSS属性速查表

    前面的话 本文将按照布局类属性.盒模型属性.文本类属性.修饰类属性这四个分类,对CSS常用属性进行重新排列,并最终设置为一份stylelintrc文件 布局类 1.定位 position z-inde ...

  9. [Codeforces702F]T-Shirts——非旋转treap+贪心

    题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...

  10. BZOJ 2243 染色

    树链剖分+区间染色 因为是一颗树不是森林,所以应该用树剖就行,但是LCT好像也能写.. 直接用线段树维护树上的节点,注意pushdown还有询问的时候要考虑区间相交的地方,也就是左孩子右边和有孩子的左 ...