求逆序对三种方法(归并排序,树状数组,线段树)

求逆序对有三种方法:归并排序,树状数组,线段树

第一种:归并排序求逆序对

int a[N];     //需要排序的数组
int temp[N];   //中间合并用数组
ll g_nCount;  //逆序对数量

void MergeArray(int l,int r,int mid) //合并两序列
{
    int i=l,n=mid;    //左子序列指针
    int j=mid+1,m=r;  //右子序列指针
    int k=0;          //temp数组指针
    while(i<=n&&j<=m)
    {
        if(a[i]<=a[j])
            temp[k++] = a[i++];
        else
        {
            temp[k++] = a[j++];
            //a[j]和前面每一个数都能组成逆序数对
            g_nCount+=n-i+1;
        }
    }
    while(i<=n)
        temp[k++] = a[i++];
    while(j<=m)
        temp[k++] = a[j++];
    for(int t=0;t<k;t++)   //拷贝回去
        a[l+t] = temp[t];
}

void Merge_sort(int l,int r) //归并排序,0~n-1的数组,则l=0,r=n-1
{
    if(l<r)
    {
        int mid = (l+r)>>1;
        Merge_sort(l,mid);   //左子序列排序
        Merge_sort(mid+1,r); //右子序列有序
        MergeArray(l,r,mid); //两边合并
    }
}

第二种:树状数组求逆序对

int tree[N];
int n;
struct node
{
    int val;  //输入数据的值
    int id;   //输入数据的位置
}a[N];

int b[N];     //离散化数组

bool cmp(node A,node B)
{
    if(A.val==B.val)
        return A.id<B.id;
    return A.val<B.val;
}

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

int getsum(int x)
{
    int res = 0;
    while(x)
    {
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}

void add(int x,int val)
{
    while(x<=n)
    {
        tree[x]+=val;
        x+=lowbit(x);
    }
}

void init()
{
    for(int i=1;i<=n;i++)
        tree[i]=0;
}

int get_reverse_pair_count()
{
    init();  //初始化树状数组
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++)  //离散化操作
        b[a[i].id]=i;      //将a[i]数组映射成更小的值
    int ans=0;
    for(int i=1;i<=n;i++)  //更新树状数组
    {
        add(b[i],1);       //意思是b[i]的值加1
        ans+=(i-getsum(b[i])); //求得比b[i]小的个数,则i减getsum(b[i])就是前面能够和b[i]构成逆序对的数量
    }
    return ans;
}


第一种:线段树求逆序对

待补。


猜你喜欢

转载自blog.csdn.net/baodream/article/details/80355881