poj2299 B - Ultra-QuickSort(线段树与树状数组求逆序对数)

题目:


In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,

Ultra-QuickSort produces the output
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence. Input
The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output
For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input
5
9
1
0
5
4
3
1
2
3
0
Sample Output           6         0

题目意思很简单,给你一个n个数的序列,问你最少需要交换几次使得它成为一个有序序列。显然就是求一个序列的逆序对数。

线段树的逆序对求法:每个叶子节点保存的是当前值数字的个数。根据给出的数字,我们一次放入线段树,在放入的时候,其实考虑的是,当前线段树中比该数字大的数字个数有多少,这可以通过查询操作完成。然后我们放入线段树,每次都进行这样的操作,就可以得出一个序列的,逆序对个数。


但是因为他输入的数字最大可达999999999,那么我们在寻找以及存比一个数字大的数字有多少时就会耗费很多空间时间,由于这里输入的数最多为500000个,于是可以进行离散化。即当你输入一个数时这个用这个数在数组中的下标代替这个数。然后按原数列大小排一次序,此时用代替他们的下标也会发生顺序改变。举个栗子:
原数列 9 1 0 5 4
下标    1  2 3 4 5

排序后:
原:    0 1 4 5 9
下标:3  2 5 4 1

会发现下标组成的序列的逆序数和原数列是相等的(那是肯定的咯,因为他们是同时进行了相同的交换----即排序 原数列把逆序数交换到没有,那么下标自然从没有变成和之前原序列一样了).接下来就是代码实现了,注意因为有500000个数,他们的逆序数最大会很大,于结果要用long long存。


线段树代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 555555;

int T,n,m;
int a[maxn];
int sum[4*maxn];

struct HASH
{
    int id;
    int num;
}Hash[maxn];

bool cmp(HASH a,HASH b)
{
    if(a.num!=b.num)
        return a.num
    else
       return a.id=r)
        return sum[t];
    int m=(l+r)/2;
    int ret=0;
    if(L<=m)
        ret+=query(L,R,l,m,t*2);
    if(R>m)
        return ret+=query(L,R,m+1,r,t*2+1);
    return ret;
}

int main()
{
    int n;
    ll ans;
    while(scanf("%d",&n)!=EOF&&n)
    {
        memset(sum,0,sizeof(sum));
        memset(a,0,sizeof(a));
        build(1,n,1);
        ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&Hash[i].num);
            Hash[i].id=i;
        }
        sort(Hash+1,Hash+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            ans+=query(Hash[i].id+1,n,1,n,1);
            update(Hash[i].id,1,n,1);
        }
        printf("%I64d\n",ans);
    }
}



树状数组代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 654321;
int T,n,q;
ll ans;
int c[maxn];
struct NUM
{
    int w;
    int id;
}num[maxn];

bool cmp(NUM a,NUM b)
{
    if(a.w==b.w)
        return a.id0)
    {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}

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

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


你可能感兴趣的:(线段树,树状数组)