hdu 1394(线段树) 最小逆序数

http://acm.hdu.edu.cn/showproblem.php?pid=1394

给出一列数组,数组里的数都是从0到n-1的,在依次把第一个数放到最后一位的过程中求最小的逆序数

线段树的应用,先建树,输入一个数,查询在在树中比他大的数的个数,然后把这个数更新进树里,再输入数重复操作,类似于进栈一样,先更新进树的数下标肯定是小于后更新的

这样只求到了一个数组的逆序数,还要有依次把第一个数放到最后的得到新数组的比较,这里有一个结论;如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],又增加n-1-a[i]的,就是加上n-1-2*a[i]的,再进行比较取最小的就行

code

 1 #include<cstdio>
 2 using namespace std;
 3 struct point {
 4     int l,r,sum;
 5 };
 6 point tree[5001*4];
 7 int a[5001];
 8 int n;
 9 void build(int i,int left,int right)
10 {
11     tree[i].l=left,tree[i].r=right;
12     tree[i].sum=0;
13     if (left==right) return ;
14     int mid=(left+right)/2;
15     build(i*2,left,mid);
16     build(i*2+1,mid+1,right);
17 }
18 int find(int i,int pos)
19 {
20     if (pos<=tree[i].l) return tree[i].sum;
21     int mid=(tree[i].l+tree[i].r)/2;
22     int a=0,b=0;
23     if (pos<=mid)
24        a=find(i*2,pos);
25     if (n-1>mid)
26        b=find(i*2+1,pos);
27     return a+b;
28 }
29 void update(int i,int pos)
30 {
31     if (pos==tree[i].l&&pos==tree[i].r)
32     {
33        tree[i].sum=1;
34        return ;
35     }
36     int mid=(tree[i].l+tree[i].r)/2;
37     if (pos<=mid)
38         update(i*2,pos);
39     else
40         update(i*2+1,pos);
41     tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
42 }
43 int main()
44 {
45     int ans,i,min;
46     while (~scanf("%d",&n))
47     {
48         if (n==0) break;
49         ans=0;
50         build(1,0,n-1);
51         for (i=1;i<=n;i++)
52         {
53            scanf("%d",&a[i]);
54            ans+=find(1,a[i]+1);
55            update(1,a[i]);
56         }
57         min=ans;
58         for (i=1;i<=n;i++)
59         {
60             ans=ans+n-1-2*a[i];
61             if (ans<min)
62               min=ans;
63         }
64         printf("%d\n",min);
65     }
66     return 0;
67 }
时间: 2024-08-15 15:25:59

hdu 1394(线段树) 最小逆序数的相关文章

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

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

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

HDU 1394(线段树单点更新)

题意:就是给出一串数,当依次在将第一个数变为最后一个数的过程中,要你求它的最小逆序数. 思路:可以用树状数组和线段数做.这里我是用线段树做的.建的是一棵空树,然后每插入一个点之前,统计大于这个数的有多少个,直到所有的数都插入完成,就结果了逆序树的统计. 要得出答案主要是利用了一个结论,如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],而增加n-1-a[i]的. #include<iostream> #include<cstring> #includ

线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

为什么线段树可以求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:可以从头开始往后找比当前元素小的值,也可以从后往前找比当前元素大的值,有几个逆序数就是几. 线段树就是应用从后往前找较大值得个数.(一边更新一边查) 当前个数是 n = 10 元素   9  5   3 9先加入线段树,T[9]+=1:查从T[9]到T[10]比9大的值,没有sum = 0: 5 加入线段树,T[5] += 1,查从T[5]到T[10]比5大的值,有一个9,sum +=1: 3

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

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 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,

HDU 1394 &lt;Minimum Inversion Number&gt; &lt;逆序数&gt;&lt;线段树&gt;

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

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

题意:给定一个序列,求分别将前m个数移到序列最后所得到的序列中,最小的逆序数. 分析:m范围为1~n,可得n个序列,求n个序列中最小的逆序数. 1.将序列从头到尾扫一遍,用query求每个数字之前有多少个大于该数字的数,方法如下. (1)将已经扫过的数字所对应的位置标记,通过query求该数字之后有多少个数被标记过 (2)该数字之后所有被标记的数字,都是在该数字之前出现过的(i<j),而这些数字又大于该数字(ai>aj),因此该数字之后所有的标记和就是该数字之前比该数字大的数的个数. 2.su

hdu 1394 Minimum Inversion Number 【线段树求逆序数】

之前写过树状数组的,再用线段树写一下--- 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 using namespace std; 8 #define lp (p << 1) 9 #define rp (p << 1