线段树---HDU1394Minimum Inversion Number

此题和上题略有不同,但是大体差不多,不过要把题意转换过来,题目大体意思为, 输入n, 也就是n个数,这些数为0 - (n-1), 这些数刚开始给定输入的顺序, 然后求他的逆序数,然后接着把第一个移到这个数列的末尾,这时候再求出一个逆序数,直到移动一个周期,也就是移动了n次, 求他们之中的最小的一个逆序数。

大体思路:

1. 首先建立线段树,初始化每个节点的值都为0

2. 输入原序列的同时,将原序列的逆序数求出来

  其中这个求的过程为找到它导致的逆序数为多少,就是找在它之前有多少个比它大的

3. 遍历一遍, 然后将剩下的n - 1 个序列的逆序数求出来,其中这里有个公式, 可以推导出来,就是可以这么考虑,假设这是第一次将第一个数移到数组的末尾,假设这个数为X[i], 它所导致的  整个数组的逆序数的变化为: 首先,它造成他后面数的逆序数为X[i](这里的X[i]就是它本身), 这个是当前数组中把它去掉之后减少的逆序数, 所以去掉它之后整个数组的逆序数就是 Sum -   x[i](这里Sum就是总的逆序数), 然后把它加到最后,它可以增加的逆序数就为 n - 1 - x[i], 所以变化这一次当前数组的逆序数为 Sum - x[i] + n - 1 - x[i];  这个可以这么求公式,是因  为这个题特殊, 因为数组里面的数为从0 - n-1, 而且还没有重复的。

下面是代码的实现:

 1 #include <cstdio>
 2 #include <algorithm>
 3
 4 using namespace std;
 5
 6 const int MAX = 5010 * 4;
 7 int sum[MAX];
 8 //更新跟其有关的以上所有节点
 9 void pushUp(int root)
10 {
11     sum[root] = sum[root * 2] + sum[root * 2 + 1];
12 }
13
14 void buildTree(int root, int left, int right)
15 {
16     sum[root] = 0;//初始化
17     if(left == right)
18     {
19         return;
20     }
21     int mid = (left + right) / 2;
22     buildTree(root * 2, left, mid);
23     buildTree(root * 2 + 1, mid + 1, right);
24     //pushUp(root);//这里可以不需要, 因为初始化都是0
25 }
26
27 void update(int root, int pos, int left, int right)
28 {
29     if(left == right)
30     {
31         sum[root]++;
32         return;
33     }
34     int mid = (left + right) / 2;
35     if(pos <= mid)
36         update(root * 2, pos, left, mid);
37     else
38         update(root * 2 + 1, pos, mid + 1, right);
39     pushUp(root);
40 }
41 //L, R代表要寻找的区间, left和right代表当前区间
42 int getSum(int root, int L, int R, int left, int right)
43 {
44     /*找大于L的, 因为大于L才能导致逆序数, 所以找它之前所有大于L的,
45     即在线段上区间可以这么写 */
46     if(L <= left && R >= right)
47     {
48         return sum[root];
49     }
50     int mid = (left + right) / 2;
51     int res = 0;
52     if(L <= mid)
53     {
54         res += getSum(root * 2, L, R, left, mid);
55     }
56     if(R > mid)
57     {
58         res += getSum(root * 2 + 1, L, R, mid + 1, right);
59     }
60     return res;
61 }
62
63 int main()
64 {
65     int x[MAX];
66     int n;
67     while(~scanf("%d", &n))
68     {
69         buildTree(1, 0, n - 1);
70         int Sum = 0;
71         for(int i = 0; i < n; i++)
72         {
73             scanf("%d", &x[i]);
74             //获得当前数导致的逆序数
75             Sum += getSum(1, x[i], n - 1, 0, n - 1);
76             update(1, x[i], 0, n - 1);
77         }
78         int t = Sum;
79         for(int i = 0; i < n; i++)
80         {
81             //此公式是由 Sum = Sum - x[i] + n - 1 - x[i]的变形
82             Sum += n - x[i] - x[i] - 1;
83             t = min(Sum, t);
84         }
85         printf("%d\n", t);
86     }
87
88     return 0;
89 }
时间: 2024-08-10 00:08:43

线段树---HDU1394Minimum Inversion Number的相关文章

Hdu1394Minimum Inversion Number线段树

这个网上一搜一大堆,就是先求一个,其余的for一遍搞出来. #include<stdio.h> #include<stdlib.h> #define max 5555 int sum[max * 4]; int min(int a, int b) { if (a>b) return b; else return a; } void fuqin(int a) { sum[a] = sum[a * 2] + sum[a * 2 + 1]; } void build(int l,

hdu1394--Minimum Inversion Number(线段树求逆序数,纯为练习)

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

hdu1394Minimum Inversion Number(线段树,求最小逆序数)

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

hdu1394Minimum Inversion Number树状数组求逆序对水题

//ans[i]=ans[i-1]+(n+1)-2*num[i] //num[i]为输入时的数据 //ans[i]为m=i时的逆序数 //用树状数组求ans[0]的逆序对 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=5010; int num[maxn]; int tree[maxn]; int lowbit(int i) { retu

C++-hdu1394-Minimum Inversion Number[数据结构][树状数组]

给出0~n-1的一个排列,可以整体移动,求逆序对最小值 把数字num[i]的加入,等价于树状数组的第n-num[i]位加1 因为num[i]是第 (n-1)-num[i]+1=n-num[i]大的数字,产生逆序对,只可能在其之前已经插入了数字,此时直接区间查询即可 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <queue> 5 #include <vector>

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

hdu 1394 Minimum Inversion Number(这道题改日我要用线段树再做一次哟~)

Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of

HDU1394 Minimum Inversion Number 线段树+数学

Problem Description The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, -, an, if we move the first m >= 0 numbers to the end of the