求逆序对

  1、逆序对的定义

  什么是逆序对呢?逆序对指的是在一个序列中,有x、y,满足x<y且a[x]>a[y],那么a[x]、a[y]就是一个逆序对。

  我们关于逆序对主要是求一个序列中逆序对的个数。

  2、如何求逆序对

  考虑朴素算法,对于每个x,y考虑一遍就好了,代码如下(其实我不太想打):

#include<bits/stdc++.h>
using namespace std;
int n,a[1000001],ans,i,j;
int main()
{
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        scanf("%d",&a[i]);
    ans=0;
    for (i=1;i<=n;i++)
        for (j=i;j<=n;j++)
        if (a[i]>a[j]) ans++;//判断大小关系
    pribntf("%d",ans);
    return 0;
}

  明显的,这是一个O(n2)的算法,在一些n较大的题目中并不可用。

  有什么优化方法吗?

  归并排序(然而博主并没有学这玩意儿)

  树状数组(然而博主看不懂这玩意儿)

  主席树(然而博主并不认为你想用这玩意儿求逆序对)

  那就是线段树

  线段树怎么求逆序对呢?

  普通的线段树求的是[l,r]之间的元素之和,而我们这次是可以记录数值在[l,r]之间的数的个数,从后往前扫,边扫边加,这样就可以求出逆序对了(而且还可以求出每个点的逆序对个数等等)。

  注意要离散化。

  以下是代码:

#include<bits/stdc++.h>
using namespace std;
long long z[2000001],l[2000001],r[2000001],n,d[500001],ans,i,cnt;
struct cjy{
    long long z,q;
}c[500001];
bool cjj(cjy a,cjy b)//我不会告诉你为什么结构体类型名和判断函数名叫这个
{
    return a.z<b.z;
}
inline void build(long long u,long long l1,long long r1)//线段树
{
  l[u]=l1;
  r[u]=r1;
  if (l1==r1)
    return;
  build(u*2,l1,(l1+r1)/2);
  build(u*2+1,(l1+r1)/2+1,r1);
}
inline void jia(long long u,long long l1,long long r1,long long k)
{
  if ((l[u]>r1)||(r[u]<l1)) return;
  if ((l[u]>=l1)&&(r[u]<=r1))
  {
    z[u]+=k*(r[u]-l[u]+1);
    return;
  }
  jia(u*2,l1,r1,k);
  jia(u*2+1,l1,r1,k);
  z[u]=z[u*2]+z[u*2+1];
}
inline long long qui(long long u,long long l1,long long r1)
{
  if ((l1>r[u])||(r1<l[u])) return 0;
  if ((l1<=l[u])&&(r1>=r[u])) return z[u];
  return (qui(u*2,l1,r1)+qui(u*2+1,l1,r1));  
}
int main()
{
    scanf("%lld",&n);
    for (i=1;i<=n;i++)
    {
        scanf("%lld",&c[i].z);
        c[i].q=i;
    }
    sort(c+1,c+n+1,cjj);
    build(1,1,n);
    cnt=0;
    for (i=1;i<=n;i++)
    {
        if (c[i].z>c[i-1].z) cnt++;//离散化
        d[c[i].q]=cnt;
    }
    for (i=n;i>=1;i--)
    {
        ans+=qui(1,1,d[i]-1);
        jia(1,d[i],d[i],1);
    }
    printf("%lld",ans);
    return 0;
}

  3、求逆序对的应用

  逆序对的应用还是比较多的,比如康托展开等。

posted @ 2019-10-08 19:10  冰逝  阅读(272)  评论(0编辑  收藏  举报