题意:输入一行数组,可以把数组的第一个挪到最后一位(藉此可以整出n个不同的数组),求这些数组中,最少的数组的逆序数对数。
提示:对于每个数组的逆序数,并不需要更改数组,只需要由上一个推下一个:下一个序列的逆序数 sum = 上一个的sum - a[i] - 1 - a[i] 。
代码:
#include<iostream>
#include<cstdio>
#define L(u) (u<<1)
#define R(u) (u<<1|1)
const int M = 5005;
struct Node
{
int l,r,sum;
}node[M<<2];
int a[M];
int min (int a,int b)
{
return a > b ? b : a;
}
void Build (int u,int left,int right)
{
node[u].l = left,node[u].r = right;
node[u].sum = 0;
if (node[u].l == node[u].r)
return ;
int mid = (node[u].l + node[u].r)>>1;
Build (L(u),left,mid);
Build (R(u),mid+1,right);
}
void Update(int u,int p)
{
if (node[u].l == node[u].r){
node[u].sum ++;
return ;
}
if (p <= node[L(u)].r) Update(L(u),p);
else Update(R(u),p);
node[u].sum = node[L(u)].sum + node[R(u)].sum; //向上更新
}
int Query(int u,int p) //查找区间p~n
{
if (p <= node[u].l)
return node[u].sum;
if (p <= node[L(u)].r)
return Query(L(u),p) + Query(R(u),p);
else return Query(R(u),p);
}
int main ()
{
int n,i;
while (~scanf ("%d",&n))
{
Build(1,0,n);
int sum = 0;
for (i = 0;i < n;i ++)
{
scanf ("%d",&a[i]);//输入数组
sum += Query(1,a[i]+1);//查找区间
Update(1,a[i]);
}
int ans = sum;
for (i = 0;i < n;i ++)
{
sum += n - a[i] - a[i] - 1;
ans = min(ans,sum);
}
printf ("%d\n",ans);
}
return 0;
}