HDU2689 Sort it 逆序数-线段树单点更新
来源:互联网 发布:淘宝上6s主板是真的吗 编辑:程序博客网 时间:2024/06/18 00:46
逆序数是这样定义的:有一个序列n1,n2,n2....,对于序列中每一个元素i来说,排在其前面的数中(即1到i-1中的数),比ni大的元素的个数的总和,叫做这个序列的逆序数。
通俗点说就是,找出序列中每一个满足的这样一种关系的i和j的对数,就是对于i>j&&a(i)<a(j)。比如1,3,2,5,4这个序列,其逆序数为2,即3和2,5和4。由定义我们知道,对于一个递增序列,其逆序数显然为0。
逆序数有一个非常常用的性质:最少需经过m次交换,可以使一个序列变成升序。其中m为该序列的逆序数。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2689
分析:我们用线段树来纪录每一个区间内的数字的个数,比如[3,8]这个区间,纪录的是3,4,5,6,7,8中已经出现的数的个数,这样我们在每一次更新之后就进行一次查询,找出当前元素后面有多少个元素已经插入到线段树中了,这些元素的个数就是该数的逆序数,对于每一个元素,我们累加起来即可。
线段树实现代码如下:
#include <iostream>#include <cstdio>using namespace std;const int maxn=5005;struct segment{ int l,r; int num;}tree[maxn<<2];void build(int root,int l,int r){ tree[root].l=l; tree[root].r=r; tree[root].num=0; if(l==r) return ; int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r);}void update(int root,int v){ if(tree[root].l==v&&tree[root].r==v) { tree[root].num=1; return ; } int mid=(tree[root].l+tree[root].r)>>1; if(v<=mid) update(root<<1,v); else update(root<<1|1,v); tree[root].num=tree[root<<1].num+tree[root<<1|1].num;}int query(int root,int l,int r){ if(l<=tree[root].l&&r>=tree[root].r) return tree[root].num; int mid=(tree[root].l+tree[root].r)>>1; int sum1=0,sum2=0; if(l<=mid) sum1=query(root<<1,l,r); if(r>mid) sum2=query(root<<1|1,l,r); return sum1+sum2;}int main(){ int n,a[maxn]; while(scanf("%d",&n)!=-1) { build(1,1,n); int ans=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); ans+=query(1,a[i]+1,n); update(1,a[i]); } printf("%d\n",ans); } return 0;}
下面是用树状数组敲的代码:
/*用树状数组求逆序数:数组A代表数字i是否在序列中出现过,如果数组i已经存在于序列中,则A[i]=1,否则A[i]=0,此时Query(i)返回值为在序列中比数字i小的元素的个数,假设序列中第i个元素的值为a,那么前i个元素中比i大的元素的个数为i-Query(a).*/#include <cstdio>#include <cstring>#define MAXN 100000using namespace std;int n,tree[MAXN];int lowbit(int i){ return i&(-i);}void update(int i,int x){ while(i<=n) { tree[i]=tree[i]+x; i=i+lowbit(i); }}int query(int n){ int sum=0; while(n>0) { sum+=tree[n]; n=n-lowbit(n); } return sum;}int main (){ while(scanf("%d",&n)!=EOF) { int a,ans=0; memset(tree,0,sizeof(tree)); for(int i=1;i<=n;i++) { scanf("%d",&a); update(a,1); ans+=i-query(a); } printf("%d\n",ans); } return 0;}
0 0
- HDU2689 Sort it 逆序数-线段树单点更新
- HDU2689 Sort it【树状数组】【逆序数】
- HDU2689 Sort it (树状数组求逆序数)
- HDU2689 Sort it(树状数组求逆序数)
- HDU2689-树状数组&逆序数|分治-Sort it
- 线段树求逆序数(单点更新)
- HDU 1394 线段树单点更新求逆序数
- HDU1394(最小逆序数)-线段树单点更新
- HDU 1394(单点更新线段树求逆序数)
- Minimum Inversion Number(线段树单点更新+逆序数)
- hdu1394(最小逆序数)(线段树单点更新)
- HDU1394 线段树 单点更新 求逆序数
- HDU2689:Sort it
- hdu2689 sort it
- hdu 1394 Minimum Inversion Number(线段树之 单点更新求逆序数)
- HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)
- HDU 1394 Minimum Inversion Number(线段树:单点更新,求逆序数)
- HDU1394 Minimum Inversion Number 逆序数- 线段树单点更新求
- numel函数的用法
- WindowManager 的FLAG_NOT_TOUCH_MODAL和 FLAG_NOT_FOCUSABLE 参数
- Java线程安全简述
- DalVik学习之利器篇--如何使用smali
- ironPython 安装 numpy
- HDU2689 Sort it 逆序数-线段树单点更新
- SDK打包合并的终端代码
- 全角半角转换
- IT公司选择(转载)
- 适配iphone6
- 数据结构(c++版)第四章 字符串和多维数组
- Java语言—Eclipse导出入包、添加第三方插件(jline)、自定义jar包用cmd窗口运行
- opencv K邻近分类器的使用
- 命令窗口导入导出mysql数据库