1. 程式人生 > >求逆序 二分+樹狀陣列

求逆序 二分+樹狀陣列

#include<iostream>
#include<stdio.h>
using namespace std;
int a[100001],n,temp[100001];
long long ct=0;
void merg(int first,int last){
    int mid=(first+last)/2;
    int i=first,j=mid+1,k=first;
    while(i<=mid&&j<=last){
        if(a[i]>a[j]){
            temp[k++]=a[j++];//把小的放進來。
            //由於是有序的,所以i之後的肯定也都比j大 ,所以直接加上即可。
            ct+=mid-i+1;
        }else{
            temp[k++]=a[i++];
        }
    }
     //把剩下的按序放進陣列。
     while(i<=mid){
            temp[k++]=a[i++];
        }
    while(j<=n){
        temp[k++]=a[j++];
    }
    for(int u=first;u<=last;u++)
        a[u]=temp[u];
}

void mergeSort(int first,int last){
    if(first>=last)return;
    if(first<last){
        int mid=(first+last)/2;
        mergeSort(first,mid);
        mergeSort(mid+1,last);
        merg(first,last);
    }
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    mergeSort(0,n-1);
    cout<<ct;
    //printf("%I64d",ct);
}

我寫的二分的方法,但是會超時。。。然後看了大佬們的樹狀陣列,又複習了樹狀陣列,它是便於查詢與更新,m次更新複雜度為mlgn,時間複雜度低,效率高,c[i]的意思是它包括從i起(包括i)的lowbit(i)[i&-i],個數的和,-i表示取反加一。

/* 
用樹狀陣列求逆序數:陣列A代表數字i是否在序列中出現過, 
如果陣列i已經存在於序列中,則A[i]=1,否則A[i]=0, 
此時Query(i)返回值為在序列中比數字i小的元素的個數, 
假設序列中第i個元素的值為a, 
那麼前i個元素中比i大的元素的個數為i-Query(a). 
*/  
#include <cstdio>  
#include <cstring>  
#define MAXN 100000  
using namespace std;  
int n,tree[MAXN];  
int lowbit(int i)  
{  
    return i&(-i);  
}  
void update(int i,int x)  
{  
    while(i<=n)  
    {  
        tree[i]=tree[i]+x;  
        i=i+lowbit(i);  
    }  
}  
int query(int n)  
{  
    int sum=0;  
    while(n>0)  
    {  
        sum+=tree[n];  
        n=n-lowbit(n);  
    }  
    return sum;  
}  
int main ()  
{  
    while(scanf("%d",&n)!=EOF)  
    {  
        int a,ans=0;  
        memset(tree,0,sizeof(tree));  
        for(int i=1;i<=n;i++)  
        {  
            scanf("%d",&a);  
            update(a,1);  
            ans+=i-query(a);  
        }  
        printf("%d\n",ans);  
    }  
    return 0;  
}  
PS:我真的是不太明白這一句:
 ans+=i-query(a);  
真的不明白,query(a)表示到a為止的,不明白,再想想。。。。

明白了:

query(a)表示輸入當前的狀態時,比a小的元素的個數,那麼用i(當前計算元素所處的位置),減去小於它的元素個數,剩下的便是大於等於它的元素個數,那麼就求出了當前數的逆序,對每一個輸入的數,做判斷。

求序列的逆序對每個數求其左邊大於它的元素的個數。該演算法的複雜度O(nlogn),對n個數進行遍歷,更新樹狀陣列複雜度為logn。