ACM Minimum Inversion Number 解题报告 -线段树

C - Minimum Inversion Number

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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
 //线段树专题解题。
//其实一开始没想通,后来手动模拟了一下整个树建立的过程就全部清楚了。
//详细AC代码在下面:
 #include"iostream"
#include"algorithm"
#include"cstdio"
#include"cstring"
#include"cmath"
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MX = +;
int sum[MX<<];
void PushUp(int rt) {
sum[rt]=sum[rt<<]+sum[rt<<|]; //更新节点 父节点为子节点之和
} void Build(int l,int r,int rt) {
sum[rt]=; //建立一棵空树 【这里之前放在了判断里面,叶节点确实清空了,枝节点漏掉了】
if(r==l) return ;
int m=(r+l)>>;
Build(lson);//建立左节点
Build(rson);//建立右节点
} void UpData(int p,int l,int r,int rt) {
if(r==l) { //找到并更新目标点
sum[rt]++;
return ;
}
int m=(r+l)>>;
if(p<=m) UpData(p,lson); //如果不是目标点向左右寻找
if(p >m) UpData(p,rson);
PushUp(rt);//将更新过的每个点的子节点的和更新。
} int Query(int L,int R,int l,int r,int rt) {
if(L<=l&&R>=r) //大小超过整个范围
return sum[rt]; //返回总数
int m=(r+l)>>;
int ret=;
if(L<= m) ret += Query(L,R,lson); //比x[i]大的树的左值和
if(R > m) ret += Query(L,R,rson); //比x[i]大的树的右值和
return ret;
}
int x[MX];
int main() {
int n;
int sums;
char s[];
while(~scanf("%d",&n)) {
sums=;
Build(,n-,); //【这里应该从0~n-1比较好,从1~n的话0的位置不好放在哪里了。后面也就一样了。】
for(int i=; i<n; i++) {
scanf("%d",&x[i]);
sums+=Query(x[i],n-,,n-,);
UpData(x[i],,n-,);
}
int ret=sums;
for(int i=; i<n; i++) {
sums=sums+n-*x[i]-;
ret=min(ret,sums);
}
printf("%d\n",ret);
}
return ;
}
 
 
上一篇:Sersync + Rsync 代码分发


下一篇:$scope 的生命周期