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
",min);
65     }
66     return 0;
67 }
原文地址:https://www.cnblogs.com/JJCHEHEDA/p/4756769.html