HDU 1394 树状数组+离散化求逆序数

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

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

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

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

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

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

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

带着代码再加深理解:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define MAXN 5005
 6 using namespace std;
 7 struct node
 8 {
 9     int val;
10     int tag;
11 }num[MAXN];
12 int t;
13 int r[MAXN],c[MAXN];//c[MAXN]为已经离散化的树状数组元素
14 bool cmp(node a,node b)
15 {
16     return a.val<b.val;
17 }
18 int lowbit(int x)
19 {
20     return x&(-x);
21 }
22 void update(int x)
23 {
24     while(x<=t)
25     {
26         c[x]+=1;
27         x+=lowbit(x);
28     }
29 }
30 int s(int x)
31 {
32     int sum=0;
33     while(x>0)
34     {
35         sum+=c[x];
36         x-=lowbit(x);
37     }
38     return sum;
39 }
40 int main()
41 {
42     int i,j,ans,min;
43     while(cin>>t)
44     {
45         ans=0;
46         memset(c,0,sizeof(c));
47         for(i=1;i<=t;i++)
48         {
49             scanf("%d",&num[i].val);
50             num[i].tag=i;
51         }
52         sort(num+1,num+t+1,cmp);
53         for(i=1;i<=t;i++)
54         {
55             r[num[i].tag]=i;//进行离散化
56         }
57         for(i=1;i<=t;i++)
58         {
59             update(r[i]);
60             ans=ans+i-s(r[i]);
61         }
62         min=ans;
63         for(i=1;i<t;i++)
64         {
65             ans=ans-r[i]+1+t-r[i];
66             min=ans<min?ans:min;
67         }
68         printf("%d\n",min);
69     }
70     return 0;
71 }
时间: 2024-10-14 15:21:06

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

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

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 9 1 0 5

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

POJ2299 Ultra-QuickSort【树状数组】【逆序数】

题目链接: http://poj.org/problem?id=2299 题目大意: 给你一个包含N个整数的序列,只能通过交换相邻的数字,最终变为升序顺序,问:最少需要多少次交换. 思路: 其实就是问冒泡排序的交换次数.其实就是求原序列的逆序数.用归并排序.线段树.树状数组都可以做. 但是如果用线段树和树状数组来做的话,因为元素个数是500000,但是元素值范围却是999999999,需 要先离散化.这里用间接排序的方法.用一个数组Arr[]存放原序列的值,另一个数组Id[]存放原序列编号 (1

HDU 1394 树状数组(逆序数)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 10100    Accepted Submission(s): 6192 Problem Description The inversion number of a given number sequence a1, a2, ..., an

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

题目大意: Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ada≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad. A1,A2?AnA1,A2?An.  1≤n≤500001≤n≤50000  0≤Ai≤1e9 基本思路: 最朴素的思想就是算出所有顺序对所有逆序对

hdu 1394(树状数组)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16948    Accepted Submission(s): 10292 Problem Description The inversion number of a given number sequence a1, a2, ..., a

hdu 3333(树状数组 + 离散化 + hash)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3847    Accepted Submission(s): 1306 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

Segment Game (hdu 5372 树状数组+离散化)

Segment Game Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 534    Accepted Submission(s): 132 Problem Description Lillian is a clever girl so that she has lots of fans and often receives gift

poj 2299 Ultra-QuickSort(线段树/树状数组/归并 求逆序对)

Problem: 2299 User: shu_dayang Memory: 7380K Time: 500MS Language: C++ Result: Accepted Source Code//树状数组 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> typedef long long LL; #define MAXN 500005 #define M