POJ2299 Ultra-QuickSort

题目链接:http://poj.org/problem?id=2299


题目大意:通过交换相邻两个的序列元素,使得序列为升序,问你最小需要多少次。

解题思路:实质就要你求该序列的逆序数。求逆序数有两种求法。一种是归并排序,还有一种就是树状数组。

1.归并排序:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define INF 0xfffffff
using namespace std;

typedef __int64 ll;
int a[500005];
int L[250005],R[250005];
ll cnt;

void Merge(int a[],int l,int mid,int r)
{
    int n1 = mid-l+1;
    int n2 = r-mid;
    int i,j,k;
    for(i = 1; i <= n1; i++)
        L[i] = a[l+i-1];
    for(i = 1; i <= n2 ;i++)
        R[i] = a[mid+i];
    L[n1+1] = INF;
    R[n2+1] = INF;
    i = 1;
    j = 1;
    for(k = l; k <= r; k++)
    {
        if(L[i] <= R[j])
        {
            a[k] = L[i];
            i++;
        }
        else
        {
            a[k] = R[j];
            j++;
            cnt += (ll)(n1-i+1);
        }
    }
}

void Merge_sort(int a[],int l,int r)
{
    if(l < r)
    {
        int mid = (l+r)>>1;
        Merge_sort(a,l,mid);
        Merge_sort(a,mid+1,r);
        Merge(a,l,mid,r);
    }
}

int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        int i;
        cnt = 0;
        for(i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        Merge_sort(a,1,n);
        printf("%I64d\n",cnt);
    }
    return 0;
}

2.树状数组

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef __int64 ll;
int n;
int d[500005];//离散化后的数组
int c[500005];

struct node
{
    int id;
    int num;
}v[500005];

bool cmp(node a,node b)
{
    if(a.num == b.num)
        return a.id < b.id;
    return a.num < b.num;
}

int lowbit(int x)
{
    return x&(-x);
}

void update(int x)
{
    while(x <= n)
    {
        c[x] += 1;
        x += lowbit(x);
    }
}

int getsum(int x)
{
    int sum = 0;
    while(x)
    {
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}

int main()
{
    while(scanf("%d",&n),n)
    {
        int i;
        ll ans = 0;
        for(i = 1; i <= n; i++)
        {
            scanf("%d",&v[i].num);
            v[i].id = i;
        }
        sort(v+1,v+n+1,cmp);
        for(i = 1; i <= n; i++)
            d[v[i].id] = i;
        memset(c,0,sizeof(c));
        for(i = 1; i <= n; i++)
        {
            update(d[i]);
            ans += (ll)(i-getsum(d[i]));
        }
        printf("%I64d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(归并排序,逆序数,树状数组)