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*();

B[J]>=B[I]

也就是求逆序对;

求逆序对的方法主要有两种:

归并排序;

树状数组;

这里两种方法都学习一下:

1.之前对于树状数组的印象就只有单点修改和区间求和

一直觉得lowbit是一个神奇的东西(至今没有搞懂原理)

上网搜了一下用树状数组求逆序对的方法,发现有一个大神写的很棒....看得很明白(感谢~~)

顺便学了一下离散化,也就是文中的:

        for(i=1;i<=n;i++)

        {

            scanf("%d",&in[i].v);

            in[i].order=i;

        }

        sort(in+1,in+n+1,cmp);

        for(i=1;i<=n;i++) aa[in[i].order]=i;

有点像指针操作。(自己对离散化的初步感受是这样的)

然后就是根据树状数组的原理求逆序对了

其实一直不是很清楚树状数组的原理,翻了翻书才有一点点的领悟吧

1).首先是update中的c数组的理解,上面链接的那个资料中解释的过程会误以为c是统计某个数的个数的

仔细看白书会发现其实并不是这样,c数组是用来维护某一区间的区间和的

getsum的操作也就是把沿途中的长条所表示的区间和加起来,这样可以节省时间(注意理解图)

2).具体的,标程中的c是用来记录在某个区间里有多少个数比i小

3).理解lowbit的过程,同样需要仔细回看白书的解释

无论是i=t-n;i+=lowbit(i)或是i-=lowbit(i)都是一个找父亲的过程

4).其实说白了lowbit到底有什么用呢,其实也就是节省了时间,做到快速简便而已吧

嗯...这样的话,对于树状数组的原理算是搞懂了QAQ感觉这种东西很容易忘记怎么办?

给以后的自己一个忠告呗~先看白书,好好理解图,再看自己的感悟,最后看链接资料;

2.另一种方法就是很传统的用:归并排序求逆序对

这种算法求逆序对也很容易理解,简单的说也无非就是基于快排思想+统计个数

主要的程序:p版的...不要在意这些细节...

procedure mergesort(l,r:longint);
var
  mid,i,j,k:longint;
begin
  if l=r then exit;
  mid:=(l+r) div 2;
  mergesort(l,mid);
  mergesort(mid+1,r);
  i:=l;j:=mid+1;k:=l;
  while (i<=mid) and (j<=r) do
    if v[i]<v[j] then
      begin
        push(k,i);
        ans:=ans+r-j+1;//在l..mid 和 mid+1 ..r中j处于[mid+1,r]中且这段是升序的,那么如果v[j]>v[i]那么v[j..r]都会大于//v[i]这和求逆序对有异曲同工之妙
      end
        else
          push(k,j);
  while i<=mid do push(k,i);
  while j<=r do push(k,j);
  for i:=l to r do v[i]:=temp[i];
end;

根据推导建立等式,之后输出ans即可

很好理解就不多说了...

晚安民那

时间: 2024-10-05 23:50:33

Day2:T4求逆序对(树状数组+归并排序)的相关文章

求逆序对[树状数组] jdoj

求逆序对 题目大意:给你一个序列,求逆序对个数. 注释:n<=$10^5$. 此题显然可以跑暴力.想枚举1到n,再求在i的后缀中有多少比i小的,统计答案即可.这显然是$n^2$的.这...显然过不去,我们思考如何优化?显然,这里的有些过程是重复的.我们将这个序列设为a序列,对于两个1到n中的整数i<j,在j后面的数我们进行了多次重复枚举,我们思考如何优化.容易想到用一个桶来记录.只需要记录对于每一个数来讲,我后面有多少个数是比我小的,只需要将桶中的数累加即可.但是,我们必须记录是这个数之后的桶

【2018.12.15】【考试总结】【模拟+逆序对+树状数组+贪心+multiset】爆零之旅

这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的QAQ 答题卡 [题目背景] 八月是个悲惨的月份.先不谈炎热的天气,对于新生来说,八月意味着军训: 而对于高二高三的同学来说,八月意味着开学考试.而考试就意味着改卷,改卷 也就意味着答题卡.不幸的是,学校读答题卡的机器的评分软件坏了,wyx 就被 老师要求写一个评分的程序. [问题描述] 软件需要读入学生的姓名.试题答案以及学生的答题卡信息. 学生姓名 学校的信息管理系统中存储了所有学生的姓名,一共 名学生.每个学生的 名字的组成只

POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组

http://poj.org/problem?id=2299 求逆序对最简单的绝对不会是树状数组,一定是归并排序(认真),不过树状数组会不会快一点呢?理论上应该是树状数组快一点(假如不进行离散化). #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set

BZOJ3295 CQOI2011 动态逆序对 树状数组套线段树

离线倒着做,每次加入一个节点后新增的逆序对数量就是其左边大于它的数的个数(左边数的总数-左边小于它的数的个数)+右边小于它的数的个数 用树状数组维护求和,对于树状数组中每个节点v所对应的区间线段树维护区间[l,r]中大于v的数的个数. 最后唯一的问题就是指针版线段树MLE-- #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <alg

BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树

题意:链接 方法:树状数组套线段树 解析: 这题基本上写的都是什么CDQ点分治,主席树之类的,然而这我都并不会,所以写了一发平衡树套线段树想卡时卡过去,然而我并没有得逞,T的不要不要的,这里用平衡树套线段树的方法参见我的题解:排队.这道题比那道更要简单. 然后我就打算弃坑了~不过看140142做这道题做的热火朝天的,还是打算回来做一下,yy下树状数组套线段树,然后去看hz的题解,只看懂他写理论部分了,代码部分不知所云,所以还是还是得yy.引用理论部分. 删除某个数,只要统计它之前还存在的比它大的

luogu P1908 逆序对 |树状数组

题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为"逆序对"的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. Update:数据已加强. 输入格式 第一行,一个数n,表示序列中有n个数. 第二行n个数,表示给定的序列.序列中每个数字不超过10

Inversion (hdu 4911 树状数组 || 归并排序 求逆序对)

Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 2003    Accepted Submission(s): 787 Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers fo

逆序对 (树状数组 | | 归并排序

数组前面的一个元素 大于等于 后面的一个元素就是一个逆序对: 树状数组可以快速求前缀和,利用这一特性,可以求逆序对个数,见下: 用数组c[ i ]记录数组a[ n ]中i这一元素出现的次数 ,当a[ n ]中元素较大时可以离散化处理. 将a[ n ]从a[n -1]到a[0] 依次存到树状数组中,每存一个,对存的元素i求一次c[i]的前缀和, 这就是当前已扫描过的比i小的元素的个数,由于a[n]是倒着扫描的,所以此时比i小的元素都对应一个逆序对,统计之. #include <cstdio> #

【模板】逆序队(树状数组/归并排序)

P1908 逆序对 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. 输入输出格式 输入格式: 第一行,一个数n,表示序列中有n个数. 第二行n个数,表示给定的序列. 输出格式: 给定序列中逆序对的数目