HDU_1394 Minimum Inversion Number(线段树)

  /*设原序列的逆序数为sum,每往后移一个数,可以找到规律sum += n-2*num[i]-1;
(n为元素个数,num[i]为移动的数);

求原序列的逆序数时可以用线段树,每输入一个数,先querry [输入的数,n]中元素的
个数,再把num[i]插入到线段树中。。。
*/

#include
<iostream>
#include
<cstdio>
#include
<cstring>
#define L(x) x << 1
#define R(x) x << 1 | 1

using namespace std;

const int N = 5005;

struct node
{
int l, r;
int sum;
}node[N
*4];

int num[N];

void creat(int t, int l, int r)
{
node[t].l
= l;
node[t].r
= r;
node[t].sum
= 0;
if(l == r)
return;
int mid = (l + r) >> 1;
creat(L(t), l, mid);
creat(R(t), mid
+ 1, r);
}

void updata(int t, int x)
{
node[t].sum
++;
if(node[t].l == node[t].r)
return;
int mid = (node[t].l + node[t].r) >> 1;
if(x <= mid)
updata(L(t), x);
else
updata(R(t), x);
}

int query(int t, int l, int r)
{
if(node[t].l >= l && node[t].r <= r)
return node[t].sum;
int mid = (node[t].l + node[t].r) >> 1;
if(l > mid)
return query(R(t), l, r);
else if(r <= mid)
return query(L(t), l, r);
else
return query(L(t), l, mid) + query(R(t), mid+1, r);
}

int main()
{
//freopen("data.in", "r", stdin);

int n, sum, i, min;
while(scanf("%d", &n) != EOF)
{
creat(
1, 0, n-1);
sum
= 0;
for(i = 1; i <= n; i++)
{
scanf(
"%d", &num[i]);
sum
+= query(1, num[i], n-1);
updata(
1, num[i]);
}

min
= sum;
for(i = 1; i <= n; i++)
{
sum
+= n-2*num[i]-1;
if(min > sum) min = sum;
}
printf(
"%d\n", min);
}
return 0;
}

原文地址:https://www.cnblogs.com/vongang/p/2176648.html