poj 2299 Ultra-QuickSort(线段树,离散化求逆序数)

题目链接:

http://poj.org/problem?id=2299


分析与总结:

一看到这题的第一反应就觉得是求逆序数 = =|

先用归并排序求逆序数AC之,这应该是速度最快的一种求逆序数方法,391MS

然后用树状数组做,因为每个元素范围0 ≤ a[i] ≤ 999,999,999, 太大了,所以我用map离散化了,结果超时了...

后来发现,其实不需要用map来映射,之所以用map是应为元素的值太大了,但是其实不需要映射元素的值,只需要映射元素的下标位置即可!而最多只有50W个数,可以直接用数组保存,这样就可以O(1)的时间得到映射的值了。

最后又再用线段树搞了下,用了922MS...



代码:


1. 树状数组+离散化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int MAXN = 500005;

typedef long long int64;
int n,arr[MAXN],rank[MAXN]; 
int64 c[MAXN], cnt,id;

struct node{
    int val, id;
    friend bool operator<(const node&a,const node&b){
        return a.val < b.val;
    }
}tmp[MAXN];
inline int lowbit(int x) {return x&(-x);}

int64 sum(int x){
    int64 ret=0;
    while(x>0){
        ret += c[x];
        x -= lowbit(x);
    }
    return ret;
}
void add(int x){
    while(x <= id){
        ++c[x];
        x += lowbit(x);
    }
}

int main(){
    while(~scanf("%d",&n) && n){
        memset(c, 0, sizeof(c));
        for(int i=0; i<n; ++i){
            scanf("%d",&arr[i]);
            tmp[i].val = arr[i];
            tmp[i].id = i;
        }
        sort(tmp, tmp+n);
        id = 1;
        for(int i=0; i<n; ++i){
            if(!i || tmp[i].val!=tmp[i-1].val)
                rank[tmp[i].id] = id++;
            else
                rank[tmp[i].id] = rank[tmp[i-1].id];
        }
        int64 ans=0;
        for(int i=0; i<n; ++i){
            int x = rank[i];
            ans += sum(id)-sum(x);
            add(x);
        }
        printf("%lld\n",ans);
        cnt = 0;
    }
    return 0;
}

2. 线段树+离散化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid ((left+right)>>1)
#define lson rt<<1, left, m
#define rson rt<<1|1,m+1,right
using namespace std;
const int MAXN = 500010;

typedef long long int64;
int n,arr[MAXN],rank[MAXN]; 
int64 c[MAXN<<2];

struct node{
    int val, id;
    friend bool operator<(const node&a,const node&b){
        return a.val < b.val;
    }
}tmp[MAXN];

void update(int rt,int left,int right,int data){
    ++c[rt];
    if(left==right) return;
    int m = mid;
    if(data <= m) update(lson,data);
    else update(rson,data);
}
int64 query(int rt,int left,int right,int l,int r){
    if(left==l && right==r) return c[rt];
    int m = mid;
    if(r <= m) return query(lson,l,r);
    else if(l > m) return query(rson,l,r);
    else return query(lson,l,mid)+query(rson,mid+1,r);
}

int main(){
    while(~scanf("%d",&n) && n){
        memset(c, 0, sizeof(c));
        memset(rank, 0, sizeof(rank));
        for(int i=0; i<n; ++i){
            scanf("%d",&arr[i]);
            tmp[i].val = arr[i];
            tmp[i].id = i;
        }
        sort(tmp, tmp+n);
        for(int i=0; i<n; ++i){
            rank[tmp[i].id] = i+1;
        } 
        int64 ans=0;
        for(int i=0; i<n; ++i){
            int x = rank[i];
            ans += query(1,1,n+1,x+1,n+1);
            update(1,1,n+1,x);
        }
        printf("%lld\n",ans);
    }
    return 0;
}



3. 归并排序求逆序数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 500005;

typedef long long int64;
int n,arr[MAXN], tmp[MAXN]; 
int64 cnt;

void merge_sort(int *A,int x,int y,int *T){ 
    if(y-x > 1){  
        int m=(x+y)>>1;   // 划分  
        int p=x, q=m, i=x;  
        merge_sort(A,x,m,T);  
        merge_sort(A,m,y,T);  
        while(p<m || q<y){      
            if(q>=y || (p<m && A[p] <= A[q])) T[i++] = A[p++];  
            else { T[i++] = A[q++]; cnt += m-p; } 
        }  
        for(i=x; i<y; ++i) A[i]=T[i];  
    }  
}  

int main(){
    while(~scanf("%d",&n) && n){
        for(int i=0; i<n; ++i){
            scanf("%d",&arr[i]);
            tmp[i] = arr[i];
        }
        cnt = 0;
        merge_sort(arr,0,n,tmp);
        printf("%lld\n",cnt);
    }
    return 0;
}



—— 生命的意义,在于赋予它意义士。

原创http://blog.csdn.net/shuangde800By D_Double (转载请标明)





你可能感兴趣的:(Quicksort)