zoukankan      html  css  js  c++  java
  • 填坑之归并排序

    填坑之归并排序

    归并排序:

    复杂度:稳定的O(nlogn)

    空间:两倍空间

    应用:求逆序对

    算法思想:将数据划分为若干个有序的小区间,每次将两个区间合并时也许满足有序

    逆序对 洛谷P1908

    方法一:利用归并排序的思想,每次出现右端区间的数小于左区间时,统计出现的逆序对数

    #include <iostream>
    #include <cstdio>
    using namespace std;
    #define ll long long
    #define R register
    int n;long long ans=0;
    int a[500005+5],rr[500005+5];
    void msort(int l,int r)
    {
        int mid=l+r>>1;
        if(l==r)return;
        msort(l,mid);msort(mid+1,r);
        int x=l,y=mid+1,tot=l;
        while(x<=mid&&y<=r)
            if(a[x]<=a[y])rr[tot++]=a[x++];
            else rr[tot++]=a[y++],ans+=(ll)mid-x+1;
        while(x<=mid)rr[tot++]=a[x++];
        while(y<=r)rr[tot++]=a[y++];
        for(R int i=l;i<=r;i++)a[i]=rr[i];
    }
    int main()
    {
        scanf("%d",&n);
        for(R int i=1;i<=n;i++)scanf("%d",&a[i]);
        msort(1,n);
        printf("%lld
    ",ans);
        return 0;
    }
    
    

    以下update于2019.815

    方法二:树状数组

    这个其实也有两种写法

    洛谷题解里有一篇讲得很不清晰,文字里说的是一种写法,代码里却是另一种写法,害得我想了半天

    两种写法

    第一种写法:(可以于可重复数据)

    先保证i<j 再保证a[i]>a[j]

    即按原顺序枚举,再在其离散化后的数组中的rank在数状数组中+1

    例题:洛谷2019年7月月赛题小鱼比可爱(加强版)

    题意:求所有区间逆序对总个数

    显然一对逆序对a[i],a[j]对答案的贡献次数为 i*(n-j+1)

    所以add(rank[i],i) ans=ans+(n-i+1)*sum(rank[i]-1)

    这道题显然用归并也能做,但需要记录一个前缀和数组防止T掉

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    using namespace std;
    #define ll __int128
    #define maxn 1000100
    ll n;
    ll a[maxn],b[maxn],c[maxn],ran[maxn];
    ll lowbit(ll x){return x&(-x);}
    ll read()
    {
        ll ret=0;
        char ch=getchar();
        while(ch>'9'||ch<'0')ch=getchar();
        while(ch>='0'&&ch<='9')
        {
            ret=ret*10+ch-'0';
            ch=getchar();
        }
        return ret;
    }
    void add(ll x,ll v)
    {
        while(x<=n)
        {
            c[x]+=v;
            x+=lowbit(x);
        }
    }
    ll query(ll x)
    {
        ll ret=0;
        while(x!=0)
        {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    bool cmp(ll x,ll y)
    {
        return x>y;
    }
    ll ans=0;ll m;
    void write(ll x)
    {
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    ll posi(ll x)
    {
        ll l=1,r=m,mid,ans;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(b[mid]>=x)
            {
                ans=mid;l=mid+1;
            }
            else r=mid-1;
        }
        return ans;
    }
    int main()
    {
        n=read();
        for(ll i=1;i<=n;i++)
        {
            a[i]=read();b[i]=a[i];
        }
        sort(b+1,b+n+1,cmp);
        m=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;i++)
        {
            ran[i]=posi(a[i]);
        }
        for(ll i=1;i<=n;i++)
        {
            ans+=(ll)(n-i+1)*query(ran[i]-1);
            add(ran[i],i);
        }
        write(ans);
        return 0;
    }
    

    第二种写法:(只能用于不重复数据)

    先保证a[i]>a[j]再保证i<j

    即记录一个数组b[i]记录了第i大的数在原数组中排第几,然后从1到n枚举i,将树状数组中的第b[i]个的值+1

  • 相关阅读:
    Linux-modules software
    Vim-Vundle-plugins-scripts
    Ubuntu-1404 GDB 调试C++报错
    Objdump-查看汇编指令
    Tornado-简介
    nginx-简介
    CentOS7 + linux kernel 3.10.94 compile 简记
    2020寒假学习笔记15------Spark基础实验
    2020寒假学习笔记14------Python基础语法学习(三)
    2020寒假学习笔记13------Python基础语法学习(二)
  • 原文地址:https://www.cnblogs.com/Akaina/p/11335967.html
Copyright © 2011-2022 走看看