<Sicily>Inversion Number(线段树求逆序数)

一、题目描述

There is a permutation P with n integers from 1 to n. You have to calculate its inversion number, which is the number of pairs of Pi and Pj satisfying the following conditions: iPj.

二、输入

The input may contain several test cases.

In each test case, the first line contains a positive integer n (n<=100000) indicating the number of elements in P. The following n lines contain n integers making the permutation P.

Input is terminated by EOF.

三、输出

For each test case, output a line containing the inversion number.

四、解题思路

题意:求逆序

思路:
1.对整个输入序列,从前往后扫,统计比a[i]小的,在a[i]后面的有多少个,进行累加。这种方法是暴力做法。复制度为n^2。

2)统计a[i]前面的比它大的数
这样利用输入时,已经知道前面的序列,每输入一个数,就把这个数的num[i]值加1,然后统计比这个数大的数的num和,因为这里的和一定是在这个数列中比a[i]大,且在它前面出现的数之和,再把这个和加到总逆序数sum里。

3)在统计比这个数大的数的num和这一步,可以进行优化处理,使用线段树求区间域值,时间复杂度是logn,所以总体复杂度就降到了nlogn。

4)线段树的图如下:
这里写图片描述

附:这道题也可以使用归并排序的方法。

五、代码

#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAX_NUM = 110000;

struct Node
{
    int lChild, rChild;
    int num;
}segTree[MAX_NUM*3];

void Build(int lChild, int rChild, int i)
{
    segTree[i].lChild = lChild;
    segTree[i].rChild = rChild;
    segTree[i].num = 0;
    if(lChild == rChild)return;

    int mid = (lChild + rChild) >> 1;
    Build(lChild, mid, i << 1);
    Build(mid + 1, rChild, i + i + 1);
}

void update(int t, int o)
{
    if(segTree[o].lChild == segTree[o].rChild && segTree[o].lChild == t)
    {
        segTree[o].num++;
        return;
    }

    int mid = (segTree[o].lChild + segTree[o].rChild) >> 1;
    if(t > mid) update(t, o + o +1);
    else update(t, o + o);
    segTree[o].num = segTree[o+o].num + segTree[o + o + 1].num;
}

int query(int lChild, int rChild, int i)
{
    if(segTree[i].lChild == lChild && segTree[i].rChild == rChild)
        return segTree[i].num;
    int mid = (segTree[i].lChild + segTree[i].rChild) >> 1;
    if(rChild <= mid) return query(lChild, rChild, i + i);
    else if(lChild > mid) return query(lChild, rChild, i + i + 1);
    else return query(lChild, mid, i * 2) + query(mid+1, rChild, i * 2 + 1);
}


int main()
{
    int num;
    while(cin >> num)
    {
        int dataArray[MAX_NUM];
        int inputData;
        for(int i = 0; i < num; i++)
        {
            cin >> inputData;
            dataArray[i] = inputData;
        }

        Build(1, num, 1);

        long long result = 0;

        for(int i = 0; i < num; i++)
        {
            result += query(dataArray[i], num, 1);
            update(dataArray[i], 1);
        }

        cout << result << endl;
    }

    return 0;
}
posted @ 2016-06-16 17:03  chenximcm  阅读(209)  评论(0编辑  收藏  举报