pku2299 Ultra-QuickSort

题目意思是求一个序列的逆序数,朴素的做法时间复杂度是O(n^2),其中 n < 500,000 ,结果不用说肯定是超时的;于是思路转向了O(nlogn)的算法,换言之离不开二分、树型结构等方法
这里用到的是杨挺的PDF《树状数组和线段树》里提到的方法:巧妙地将问题转化成类似求RMQ的问题,然后通过树状树组解决

1,将序列离散化,即序列内第k小的元素变成k,注意到题目已说明序列内无相同元素;离散化可通过排序和二分查找解决
2,将b[]初始化为0,遍历离散化后的序列a[1~n],每当向树状数组c[]插入a[i]前,根据c[]用O(logn)的时间求b[1]~b[a[i]]的和,即求得比a[i]先插入且比a[i]小的元素个数(放到序列上理解,就是排在a[i]前面且比a[i]小的元素个数),换算后可得比a[i]先插入且比a[i]大的元素个数,在遍历过程中将其累加到ans,即为答案
3,更新ans后置b[a[i]]为1,同时更新c[]的值(对c[]插入a[i])

排序和统计的复杂度都为O(nlogn),所以算法总复杂度是O(nlogn)

 

 

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

#define MAXN 500005
#define clr(x) memset(x,0,sizeof(x))

int a[MAXN],b[MAXN],c[MAXN],n;
__int64 ans;

int find(int x){
    
int l=1,r=n,m;
    
while(r>=l){
        m
=(l+r)/2;
        
if(x<b[m])
            r
=m-1;
        
else if(x>b[m])
            l
=m+1;
        
else
            
return m;
    }
    
return -1;
}

void discretization(){
    
int i,t;
    
for(i=1;i<=n;i++){
        t
=find(a[i]);
        a[i]
=t;
    }
}

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

int sum(int k){//求sum(b[1]~b[k])
    int i,res=0;
    
for(i=k;i>0;i-=lowbit(i))
        res
+=c[i];
    
return res;
}

void improve(int k){//插入a[i]后b[a[i]]的值有修改
    int i;
        
//若对b[k]有修改,设影响到了c[p1]、c[p2]、 ,则p1=k,pi+1=pi + lowbit(pi)
    for(i=k;i<=n;i+=lowbit(i))
        c[i]
++;
}



void build(){//建立树状数组c[]
    clr(b);
    clr(c);
    
int i,k;
    
for(i=1;i<=n;i++){
        k
=a[i];
        ans
+=i-sum(k)-1;
        b[k]
=1;
        improve(k);
    }
}

int main(){
    
int i;
    
while(scanf("%d",&n) && n){
        
for(i=1;i<=n;i++){
            scanf(
"%d",a+i);
            b[i]
=a[i];
        }
        sort(b
+1,b+n+1);
        discretization();
//离散化
        ans=0;
        build();
        printf(
"%I64d\n",ans);
    }
    
return 0;
}

 

另附合并排序求逆序数代码:

 

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

#define MAXN 500001

int a[MAXN],t[MAXN],n;
__int64 ans;

void Merge(int l,int m,int r){
    
int i=0,j=l,k=m+1;
    
while(j<=&& k<=r){
        
if(a[j]>a[k]){
            t[i
++]=a[k++];
            ans
+=m-j+1;
        }
        
else
            t[i
++]=a[j++];
    }
    
while(j<=m)
        t[i
++]=a[j++];
    
while(k<=r)
        t[i
++]=a[k++];
    
for(j=0;j<i;j++){
        a[l
+j]=t[j];
    }
}


void Mergesort(int l,int r){
    
if(l<r){
        
int m=(l+r)/2;
        Mergesort(l,m);
        Mergesort(m
+1,r);
        Merge(l,m,r);
    }
}


int main(){
    
int i;
    
while(scanf("%d",&n) && n){
        ans
=0;
        
for(i=0;i<n;i++)
            scanf(
"%d",a+i);
        Mergesort(
0,n-1);
        printf(
"%I64d\n",ans);
    }
    
return 0;
}
posted @ 2008-10-22 11:00  Beetlebum  阅读(769)  评论(0编辑  收藏  举报