您的位置:首页 > 其它

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

2015-04-05 09:54 387 查看
#include "string"
#include "iostream"
#include "cstdio"
#include "cmath"
#include "set"
#include "queue"
#include "vector"
#include "cctype"
#include "sstream"
#include "cstdlib"
#include "cstring"
#include "stack"
#include "ctime"
#include "algorithm"
#define pa pair<int,int>
#define Pi M_PI
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
using namespace std;
typedef long long LL;
const int M=5005;
//#define M 200005

int sum[M<<2];
//int ans=0,ans1=0;

inline void PushPlus(int rt)
{
//sum[rt] = max(sum[rt<<1] , sum[rt<<1|1]);
sum[rt] =sum[rt<<1] +sum[rt<<1|1];
}

void Build(int l, int r, int rt)
{
if(l == r)
{
// scanf("%d", &sum[rt]);
sum[rt]=0;
return ;
}
int m = ( l + r )>>1;

Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
PushPlus(rt);
}

/*
void build(int node, int begin, int end)
{
*/

void Update(int p, int l, int r, int rt)
{

if( l == r )
{
sum[rt] ++;
return ;
}
int m = ( l + r ) >> 1;
if(p <= m)
Update(p, l,m,rt<<1);
else
Update(p, m+1,r,rt<<1|1);

PushPlus(rt);
}

int Query(int L,int R,int l,int r,int rt)
{
if( L <= l && r <= R )
{
return sum[rt];
}
int m = ( l + r ) >> 1;
//int ans=0,ans1=0;
int ans=0;
if(L<=m)
ans+=Query(L,R,l,m,rt<<1);
if(R>m)
ans+=Query(L,R,m+1,r,rt<<1|1);
//int ans=0;
return ans;
}

int main()
{
//    int T, n, a, b;
//           // scanf("%d",&T);
//           // for( int i = 1; i <= T; ++i )
//           // {
//           //  printf("Case %d:\n",i);
//      int m;
//        scanf("%d%d",&n,&m);
//
//        Build(1,n,1);
//        char op[2];
//           //ans=0,ans1=0;
//        while(m--)
//        {
//            scanf("%s%d%d",op,&a,&b);
//           // cin>>op>>a>>b;
//           // scanf("%d %d", &a, &b);
//            if(op[0] == 'Q')
//                printf("%d\n",Query(a,b,1,n,1));
//            if(op[0] == 'U')
//                Updata(a,b,1,n,1);
/*//*/
//        }
//  //  }
// int n , m;
//    while (~scanf("%d%d",&n,&m)) {
//        Build(1 , n , 1);
//        int i;
//        for( i = 1; i<=20; ++i)
//         cout<< "seg"<<   i << "=" <sum[i] <<endl;
//        while (m --) {
//            char op[2];
//            int a , b;
//            scanf("%s%d%d",op,&a,&b);
//            if (op[0] == 'Q') printf("%d\n",Query(a , b , 1 , n , 1));
//            else Updata(a , b , 1 , n , 1);
//        }
//    }
//    return 0;
int x[M];
int n;
while (~scanf("%d",&n)) {
Build(0 , n - 1 , 1);
int sum = 0;
for (int i = 0 ; i < n ; i ++) {
scanf("%d",&x[i]);//找出比当前节点大的数加起来就可以得到逆序数了
sum += Query(x[i] , n - 1 , 0 , n - 1 , 1);
Update(x[i] , 0 , n - 1 , 1);
}
int ret = sum;
for (int i = 0 ; i < n ; i ++) {
sum += n - x[i] - x[i] - 1;
ret = min(ret , sum);
}
printf("%d\n",ret);
}
return 0;
}

首先按顺序把序列a[i]每个数插入到树状数组中,插入的内容是1,表示放了一个数到树状数组中。

然后使用sum操作获取当前比a[i]小的数,那么当前i - sum则表示当前比a[i]大的数,如此反复直到所有数都统计完,

比如

4 3 1 2

i = 1 : 插入 4 : update(4,1),sum(4)返回1,那么当前比4大的为 i - 1 = 0;

i = 2 : 插入 3 : update(3,1),sum(3)返回1,那么当前比3大的为 i - 1 = 1;

i = 3 : 插入 1 : update(1,1),sum(1)返回1,那么当前比1大的为 i - 1 = 2;

i = 4 : 插入 2 : update(2,1),sum(2)返回2,那么当前比2大的为 i - 2 = 2;

过程很明了,所以逆序数为1+2+2=5
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: