求逆序数的两个方法

1.归并排序

#include <iostream>

using namespace std;

const int maxn = 1000;

int a[maxn],b[maxn];
int ans;

void merge_sort(int x,int y){
    if(y-x>1)
    {
        int m = x+(y-x)/2;
        int p = x, q = m,i = x;
        merge_sort(x,m);
        merge_sort(m,y);
        while(p<m||q<y){
            if(q>=y||(p<m&&a[p]<=a[q])) b[i++] = a[p++];
            else {b[i++]=a[q++];ans+=m-p;}
        }
        for(int i = x;i<y;i++) a[i] = b[i];
    }
}

int main()
{
    int n;
    while(cin>>n){
       for(int i=0;i<n;i++) cin>>a[i];
       ans=0;
       merge_sort(0,n);
       cout<<ans<<endl;
       for(int i=0;i<n;i++) cout<<a[i]<<" ";cout<<endl;
    }
    return 0;
}

2.离散+树状数组

E. Infinite Inversions

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

There is an infinite sequence consisting of all positive integers in the increasing order: p = {1, 2, 3, ...}. We performed n swap operations with this sequence. A swap(a, b) is an operation of swapping the elements of the sequence on positions a and b. Your task is to find the number of inversions in the resulting sequence, i.e. the number of such index pairs (i, j), that i < j and pi > pj.

Input

The first line contains a single integer n (1 ≤ n ≤ 105) — the number of swap operations applied to the sequence.

Each of the next n lines contains two integers ai and bi (1 ≤ ai, bi ≤ 109, ai ≠ bi) — the arguments of the swap operation.

Output

Print a single integer — the number of inversions in the resulting sequence.

Sample test(s)

input

24 21 4

output

4

input

31 63 42 5

output

15

Note

In the first sample the sequence is being modified as follows: . It has 4 inversions formed by index pairs (1, 4), (2, 3), (2, 4) and (3, 4).

离散:

逆序数组:9 1  0 5 4 --> 5 2 1 4 3

这题有点特别:就是先把那些交换的点+那些中间的点(等价的几个,所以a[i].yy可能大于1)

注意:maxn要为4*1e5,因为不单只2倍的10的5次方操作!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <iomanip>
#include <map>

#define sc scanf
#define pf printf
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define CLR(x,m) memset(x,m,sizeof x);
#define LOCAL freopen("test.txt","r",stdin)
#define UCCU ios::sync_with_stdio(0);
#define XSD(i) cout << fixed << setprecision(i);
#define pii pair<int,int>
#define xx first
#define yy second

using namespace std;

typedef long long LL;
typedef double DB;

const double eps = 1e-6;
const int maxn = 400100;

map<int,int> mp,mp2;
map<int, int> :: iterator it;
pii a[maxn];
int b[maxn];
LL fen[maxn];

void add(int n, int k)
{
    for(; n < maxn; n += n & (-n))
      fen[n] += k;
}

int get(int n)
{
    int res = 0;
    for(; n > 0; n -= n & (-n))
      res += fen[n];
    return res;
}

void run()
{
    int n;
    cin>>n;
    REP(i,0,n){
        int u,v;cin>>u>>v;
        if(!mp[u]) mp[u]=u;
        if(!mp[v]) mp[v]=v;
        int temp = mp[u];
        mp[u] = mp[v];
        mp[v] = temp;
    }

    int pre=1,num=0;
    for(it = mp.begin();it!=mp.end();++it){
        int x = (*it).xx;int y = (*it).yy;
        if(x!=1&&x-pre-1){
            a[++num]=pii(x-1,x-pre-1);
            b[num]=x-1;
        }
        a[++num]=pii(y,1);
        b[num]=y;
        pre=x;
    }

    sort (b + 1, b + 1 + num);
    for (int i = 1; i <= num; i++) {
        mp2[b[i]] = i;
    }
    for (int i = 1; i <= num; i++) {
        a[i].xx = mp2[a[i].xx];
    }

    LL ans =0,tot=0;
    REP(i,1,num+1){
        ans+=1LL * (tot-get(a[i].xx))*a[i].yy;
        add(a[i].xx,a[i].yy);
        tot+=a[i].yy;
    }
    cout<<ans<<endl;
}

int main()
{
    //LOCAL;
    UCCU;//cin.tie();
    run();
    return 0;
}

时间: 2024-10-14 08:52:04

求逆序数的两个方法的相关文章

线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

为什么线段树可以求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:可以从头开始往后找比当前元素小的值,也可以从后往前找比当前元素大的值,有几个逆序数就是几. 线段树就是应用从后往前找较大值得个数.(一边更新一边查) 当前个数是 n = 10 元素   9  5   3 9先加入线段树,T[9]+=1:查从T[9]到T[10]比9大的值,没有sum = 0: 5 加入线段树,T[5] += 1,查从T[5]到T[10]比5大的值,有一个9,sum +=1: 3

NYOJ117&amp;&amp; 树状数组求逆序数

(转)树状数组可以用来求逆序数, 当然一般用归并求.如果数据不是很大, 可以一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 i- getsum( data[i] ),其中 i 为当前已经插入的数的个数, getsum( data[i] )为比 data[i] 小的数的个数i- sum( data[i] ) 即比 data[i] 大的个数, 即逆序的个数但如果数据比较大,就必须采用离散化方法.一关键字的离散化方法:所谓离散化也就是建立一个一对一的映射. 因为求逆序时只

poj 2299 Ultra-QuickSort 归并排序求逆序数对

题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题思路: 根据冒泡排序的特点,我们可知,本题只需要统计每一个数的逆序数(如果有i<j,存在a[i] > a[j],则称a[i]与 a[j]为逆序数对),输出所有的数的逆序数的和用普通排序一定会超时,但是比较快的排序,像快排又无法统计 交换次数,这里就很好地体现了归并排序的优点.典型的利用归并排序求逆

逆序对问题---求逆序数

逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反, 即前面的数大于后面的数,那么它们就称为一个逆序. 一个排列中逆序的总数就称为这个排列的逆序数.逆序数为偶数的排列称为偶排列:逆序数为奇数的排列称为奇排列. { 设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同. 如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这一个有序对称为 A 的一个逆序对,也称作逆序.逆序对的数量称作逆

POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 55048   Accepted: 20256 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

hdu 5147 Sequence II (树状数组 求逆序数)

题目链接 Sequence II Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 331    Accepted Submission(s): 151 Problem Description Long long ago, there is a sequence A with length n. All numbers in this se

HDU 4417 类似求逆序数的树状数组

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2250    Accepted Submission(s): 1092 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability

51 Nod 1107 斜率小于0的连线数量 (转换为归并求逆序数或者直接树状数组,超级详细题解!!!)

1107 斜率小于0的连线数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 二维平面上N个点之间共有C(n,2)条连线.求这C(n,2)条线中斜率小于0的线的数量. 二维平面上的一个点,根据对应的X Y坐标可以表示为(X,Y).例如:(2,3) (3,4) (1,5) (4,6),其中(1,5)同(2,3)(3,4)的连线斜率 < 0,因此斜率小于0的连线数量为2. Input 第1行:1个数N,N为点的数量(0 <= N <= 50000) 第2

ACM ICPC 2011–2012, NEERC, Northern Subregional Contest J. John’s Inversions(合并排序求逆序数对数)

题目链接:http://codeforces.com/gym/100609/attachments 题目大意:有n张牌,每张牌有红色和蓝色两面,两面分别写了一些数字,同种颜色的任意两个数字若排在前面的数字比排在后面的数字大就叫做一对逆序数.求怎样排序得到的逆序数对最少. 解题思路:其中一种颜色的数字是顺序且这种颜色数字相同时对应的另一种颜色的数字是顺序时得到的逆序数对数最少.难点在于求逆序数对数.因为数量很大O(n^2)复杂度不能满足,这里根据合并排序的原理求解每个数字前面有多少个比它大的数字,