对于求逆序数问题,学会去利用树状数组进行转换求解方式,是很必要的。

一般来说我们求解逆序数,是在给定一串序列里,用循环的方式找到每一个数之前有多少个比它大的数,算法的时间复杂度为o(n2)。

那么我们通过树状数组可以明显提高时间效率。

我们可以按照排列的顺序依次将数字放入树状数组中,并依次更新预与之相关联的树状数组元素。那么在将其更新完毕后,我们知道每个数对应的树状数组元素的左边的数肯定比它小,我们在以序列顺序依次更新树状数组时,如果有值在它前面出现,那么它对应的树状数组元素(在这个题目里存放的是个数)值必然增加,我们可以利用树状数组快速求一段区间的总和(这一段是比它小的数字的总个数)。那么用i-sum得到的就是逆序数了。

当然,另外还要注意到一点由于数字可能很大,那么我们开那么大的数组是不合理地,为此我们用离散化的方式来处理r[num[i].tag]=i;r[MAXN]存放离散数据,即用i=1;i<=t;i++从小到大表示递增的数据,以便充分使用每一个数组元素,类似于map的功能,映射。)

所以因为有这一步,所以要先sort,然后将数值离散化。这样每一个数的更新仅需o(log(n))

总的时间降为o(nlog(n))。

带着代码再加深理解:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 5005
using namespace std;
struct node
{
int val;
int tag;
}num[MAXN];
int t;
int r[MAXN],c[MAXN];//c[MAXN]为已经离散化的树状数组元素
bool cmp(node a,node b)
{
return a.val<b.val;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
while(x<=t)
{
c[x]+=;
x+=lowbit(x);
}
}
int s(int x)
{
int sum=;
while(x>)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
int i,j,ans,min;
while(cin>>t)
{
ans=;
memset(c,,sizeof(c));
for(i=;i<=t;i++)
{
scanf("%d",&num[i].val);
num[i].tag=i;
}
sort(num+,num+t+,cmp);
for(i=;i<=t;i++)
{
r[num[i].tag]=i;//进行离散化
}
for(i=;i<=t;i++)
{
update(r[i]);
ans=ans+i-s(r[i]);
}
min=ans;
for(i=;i<t;i++)
{
ans=ans-r[i]++t-r[i];
min=ans<min?ans:min;
}
printf("%d\n",min);
}
return ;
}

HDU 1394 树状数组+离散化求逆序数的更多相关文章

  1. POJ 2299 Ultra-QuickSort (树状数组+离散化 求逆序数)

    In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a seque ...

  2. CF 61E 树状数组+离散化 求逆序数加强版 三个数逆序

    http://codeforces.com/problemset/problem/61/E 题意是求 i<j<k && a[i]>a[j]>a[k] 的对数 会 ...

  3. POJ 2299 树状数组+离散化求逆序对

    给出一个序列 相邻的两个数可以进行交换 问最少交换多少次可以让他变成递增序列 每个数都是独一无二的 其实就是问冒泡往后 最多多少次 但是按普通冒泡记录次数一定会超时 冒泡记录次数的本质是每个数的逆序数 ...

  4. 树状数组||归并排序求逆序对+离散化 nlogn

    我好咸鱼. 归并排序之前写过,树状数组就是维护从后往前插入,找比现在插入的数大的数的数量. 如果值域大,可以离散化 #include <cstdio> #include <cstri ...

  5. hdu 5792 树状数组+离散化+思维

    题目大意: Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a< ...

  6. POJ 3067 - Japan - [归并排序/树状数组(BIT)求逆序对]

    Time Limit: 1000MS Memory Limit: 65536K Description Japan plans to welcome the ACM ICPC World Finals ...

  7. HDU 1394 树状数组求逆序对

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  8. [hdu 4417]树状数组+离散化+离线处理

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 把数字离散化,一个查询拆成两个查询,每次查询一个前缀的和.主要问题是这个数组是静态的,如果带修改 ...

  9. Disharmony Trees HDU - 3015 树状数组+离散化

    #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using ...

随机推荐

  1. discuz X3.1+Apache2.2+php-5.2.17+mysql5.6.14+Discuz_X3.1

    discuz X3.1+Apache2.2.25+php-5.2.17+mysql5.6.14+Discuz_X3.1 一.准备 1.httpd-2.2.25-win32-x86-no_ssl.msi ...

  2. solaris软件管理 FTP

    安装一些常用软件 一.应用程序与系统命令的关系: 系统命令文件位置在 /bin /sbin下面或为shell内部指令:完成对系统的基本管理工作:一般在字符操作界面中运行:一般包括命令字.命令选项和命令 ...

  3. 封装PDO操作数据库

    <?php class DatabaseHandler { /** * sql语句查询 */ public static function query_data ($dataName,$sql, ...

  4. Linux中du和df

    Linux运维过程中,常常发现du和df返回值不一样,偶尔会发现区别非常大. 特定情况下,可能df看到磁盘已满,可是du推断磁盘剩余空间非常大. 文件系统分配当中的一些磁盘块用来记录它自身的一些数据. ...

  5. 笔记04 WPF的Binding

    oneWay:使用 OneWay 绑定时,每当源发生变化,数据就会从源流向目标. OneTime: 绑定也会将数据从源发送到目标:但是,仅当启动了应用程序或 DataContext 发生更改时才会如此 ...

  6. 关于0基础磁盘管理(gpt UEFI...)最好的一篇文章(来自gentoo linux)

    放链接:https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Disks 顺便几张图 watermark/2/text/aHR0cDovL2 ...

  7. C# winform ListView 的右键菜单的下级菜单的选项视情况禁用方法

    ListView 和右键菜单例如以下图: 要实现功能是: 1.用户状态为[活动]时,改动用户状态为[活动]禁用,反之则反. 2.而且仅仅实用户状态为[非活动]时,[删除学员用户]才是可用状态. 功能非 ...

  8. 数据库MySQL经典面试题之SQL语句

    数据库MySQL经典面试题之SQL语句 1.需要数据库表1.学生表Student(SID,Sname,Sage,Ssex) --SID 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学 ...

  9. React项目结构

    任何一种语言.框架,在真正上手的时候,多多少少会想想怎么安排项目结构(正所谓磨刀不误砍柴工),React也不例外. google了下,拿下面3篇博客来说道说道. (1) how-to-better-o ...

  10. cookie、session及实现记住密码,自动登录

    在登录帐号.密码框下,有三种帐号登录模式可供选择,用户可根据自己的具体情况选择其中一种适合自己的模式. 1.网吧模式:勾选网吧模式后,登录的帐号会在歪歪注销/退出的时候自动清除,不会留在登录框中,可以 ...