[洛谷P1908] 逆序对|归并排序|树状数组

 题目描述 Description
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
 输入输出格式 Input/output
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
 输入输出样例 Sample input/output
样例测试点#1
输入样例:

6
5 4 2 6 3 1

输出样例:
11
 说明 description
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
 
分析:传统方法是树状数组,但是蒟蒻打起来比较困难,于是直接上归并排序。在合并的时候记录一下逆序对个数就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
int n,a[40001],h[40001],ans;
int read() //读入优化。
{
    char c=getchar();
    int a=0;
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') 
    {
          a=a*10+c-'0';
          c=getchar();
    }
    return a;
}
void merge_sort(int l,int r)
{
     if (l==r) return;
     int mid=(l+r)>>1;
     merge_sort(l,mid);
     merge_sort(mid+1,r);
     int left=l,right=mid+1;
     for (int i=l;i<=r;i++)
         if ((a[left]<a[right]||right>r)&&left<=mid)
         {
                                                    h[i]=a[left];
                                                    left++;
         }
         else
         {
             h[i]=a[right];
             right++;
             ans+=(mid-left+1); //记录逆序对个数
         }
     for (int i=l;i<=r;i++) a[i]=h[i];
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    merge_sort(1,n);
    printf("%d",ans);
    return 0;
}    
原文地址:https://www.cnblogs.com/ws-fqk/p/4470794.html