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<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
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<b.num;
    else
       return a.id<b.id;
}

void pushup(int t)
{
    sum[t]=sum[t*2]+sum[t*2+1];
}

void build(int l,int r,int t)
{
    sum[t]=0;
    if(l==r)
        return;
    int m=(l+r)/2;
    build(l,m,t*2);
    build(m+1,r,t*2+1);
    pushup(t);
}

void update(int k,int l,int r,int t)
{
    if(l==r)
    {
        sum[t]++;
        return;
    }
    int m=(r+l)/2;
    if(k<=m)
        update(k,l,m,t*2);
    else
        update(k,m+1,r,t*2+1);
    pushup(t);
}

int query(int L,int R,int l,int r,int t)
{
    if(L<=l&&R>=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<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
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.id<b.id;
    else
        return a.w<b.w;
}

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

int query_sum(int x)
{
    int sum=0;
    while(x>0)
    {
        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;
}


發佈了90 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章