【线段树】HDU 1394 Minimum Inversion Number

minimum inversion number:最小逆序数

Minimum Inversion Number

Time Limit: 2000/1000
MS (Java/Others)    Memory Limit: 65536/32768 K
(Java/Others)
Total Submission(s):
9367    Accepted Submission(s):
5754

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 seqence, we will obtain another sequence. There are
totally n such sequences as the following:

a1,
a2, ..., an-1, an (where m = 0 - the initial seqence)

a2,
a3, ..., an, a1 (where m = 1)

a3,
a4, ..., an, a1, a2 (where m = 2)

...

an,
a1, a2, ..., an-1 (where m = n-1)

You
are asked to write a program to find the minimum inversion number out of the
above sequences.

Input

The input consists of a number of test cases. Each
case consists of two lines: the first line contains a positive integer n (n
<= 5000); the next line contains a permutation of the n integers from 0 to
n-1.

Output

For each case, output the minimum inversion number on
a single line.

Sample
Input

10

1 3 6 9 0 8 5 7 4 2

Sample
Output

16

Author

CHEN, Gaoli

Source

ZOJ
Monthly, January 2003

Recommend

Ignatius.L

来源: <http://acm.hdu.edu.cn/showproblem.php?pid=1394>


先建一个空树;
逐个插入值(即输入的一个值)
1 3 6 9 0 8 5 7 4
2

插入x时 查询已经插入的线段中(x+1,n-1)之间元素的个数

如:

插入 1 时  查询 已经插入的数中2-9 之间元素的个数 
v1=0
插入 3 时  查询 已经插入的数中4-9 之间元素的个数  v2=0

插入 6 时  查询 已经插入的数中7-9之间元素的个数
  v3=0

插入 9 时  查询 已经插入的数中10-9之间元素的个数  v4=0

插入 0 时  查询 已经插入的数中1-9之间元素的个数 
 v5=4

插入 8 时  查询 已经插入的数中9-9之间元素的个数   v6=1

……

插入 2 时  查询
已经插入的数中3-9之间元素的个数   v9=7

累加v1……v9  =sum =22 即最初序列逆序数为22

线段树在这里的作用是求出 最初序列的逆序数

接下来求最小逆序数

在序列 var= 0,1,2……n-1 中

比0小的个数 = 0    比0大的个数 n-1-0

比1小的个数 = 1    比1大的个数 n-1-1

……

比vi小的个数 = var   比vi大的个数 n-1-var

把第一个数var移动到后面

比vi小的数var个就都不构成逆序了     逆序数-var

比vi大的数n-1-var个构成逆序 
       逆序数+(n-1-var)

所以

逆序数=逆序数+n-1-var-var

循环移动n次,记录最小值,即为所求。

#include<stdio.h>
#include <algorithm>
using namespace std;
#define MAXN 50000
struct
Node{
    int var;
 
  int number;
};
Node
seq[MAXN*4];
void pushUp(int index){
   
seq[index].number=seq[index*2].number+seq[index*2+1].number;
}
void build(int
l,int r,int index){
   
seq[index].number=0;
    if(l==r){
 
      return ;
 
  }
    int mid=(l+r)/2;
   
build(l,mid,index*2);
    build(mid+1,r,index*2+1);
}
int
Query(int from ,int to ,int
l,int r,int index){
    int sum=0;
 
  if(from<=l&&to>=r){
 
          return
seq[index].number;
    }
    int mid=(l+r)/2;
    if(from <=mid)
       sum+=Query(from,to,l,mid,index*2);
    if(to>mid)
       sum+=
Query(from,to,mid+1,r,index*2+1);
     
 return sum;

}
void
update(int p,int l,int
r,int index){
    if(l==r){
     
 seq[index].number++;
     
 return ;
    }
 
  int mid = (l + r) /
2;
    if (p <= mid)
        update(p ,
l,mid,index*2);
    else
        update(p ,
mid+1,r,index*2+1);
     
  pushUp(index);
}
int
main(){
    int n;
 
  while (~scanf("%d",&n))
{
    build(0,n-1,1);
    int sum=0;
 
  for(int i=0;i<n;i++){
   
    scanf("%d",&seq[i].var);
        sum+= Query(seq[i].var+1,n-1,0,n-1,1);
       
update(seq[i].var,0,n-1,1);
    }
    //
printf("%d\n",sum);
    int ans =
sum;
    for (int
i = 0 ; i <
n ; i ++) {
        sum
+= n - seq[i].var
- seq[i].var - 1;
        ans =
min(ans , sum);
    }
     printf("%d\n",ans);
 
  }
    return 0;

}

来自为知笔记(Wiz)

【线段树】HDU 1394 Minimum Inversion Number

时间: 2024-08-26 23:56:40

【线段树】HDU 1394 Minimum Inversion Number的相关文章

hdu 1394 Minimum Inversion Number(线段树)

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

HDU 1394 Minimum Inversion Number(线段树求逆序数)

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由[1,N]构成,可以通过旋转把第一个移动到最后一个. 问旋转后最小的逆序数对. 分析: 注意,序列是由[1,N]构成的,我们模拟下旋转,总的逆序数对会有规律的变化. 求出初始的逆序数对再循环一遍就行了. 至于求逆序数对,我以前用归并排序解过这道题:点这里. 不过由于数据范围是5000,所以完全可以用线

hdu 1394 Minimum Inversion Number 线段树 点更新

// hdu 1394 Minimum Inversion Number 线段树 点更新 // // 典型线段树的单点更新 // // 对于求逆序数,刚开始还真的是很年轻啊,裸的按照冒泡排序 // 求出最初始的逆序数,然后按照公式递推,结果就呵呵了 // // 发现大牛都是用线段树和树状数组之类的做的,而自己又在学 // 线段树,所以就敲了线段树. // // 线段树的节点保存一段区间( L,R )内0,1...n一共出现了多少个. // 因为每个数是0,1,2...n-1且没有重复的数字. /

HDU 1394 Minimum Inversion Number(线段树求逆序对)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1394 解题报告:给出一个序列,求出这个序列的逆序数,然后依次将第一个数移动到最后一位,求在这个过程中,逆序数最小的序列的逆序数是多少? 这题有一个好处是输入的序列保证是0 到 n-1,所以不许要离散化,还有一个好处就是在计算在这个序列中比每个数大和小的数一共有多少个的时候可以在O(1)时间计算出来,一开始我没有意识到,还傻傻的用了两层for循环来每次都计算,当然这样果断TLE了.把一个数从第一个移

HDU 1394 Minimum Inversion Number (数据结构-线段树)

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

HDU 1394 Minimum Inversion Number.(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 ~~~~ 早起一发线段树,开心又快乐.这题暴力也能水过,同时线段树的效率也就体现的尤为明显了,看了大牛的博客,说是还可以用树状数组,点树和合并序列写,现在还不懂,留着以后在写吧. ~~~~ 大致题意:给定一个数字序列,同时由此可以得到n个序列, 要求从n个序列中找到逆序数最小的序列,输出最小逆序数. 首先介绍下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU - 1394 Minimum Inversion Number (线段树求逆序数)

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 seq