离散化加树状数组求逆序数。

来源:互联网 发布:团子少女 知乎 编辑:程序博客网 时间:2024/06/10 01:59

【转自BLOG】点击打开链接

【1 POJ.2299】

离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围 因为其中需排序的数的范围0---

999999999;显然数组不肯能这么大;而N的最大范围是500000;故给出的数一定可以与1.。。。N建立一个一一映射;

 

这里用一个结构体

struct Node

 {

      int v,order;

 }a[510000];

和一个数组aa[510000];

 

其中v就是原输入的值,order是下标;然后对结构体按v从小到大排序;此时,v和结构体的下标就是一个一一对应关系,而且

满足原来的大小关系;

for(i=1;i<=N;i++)

     aa[a[i].order]=i;

 

然后a数组就存储了原来所有的大小信息;比如 9 1 0 5 4 ------- 离散后aa数组就是 5 2 1 4 3;具体的过程可以自己

用笔写写就好了。

 

离散之后,怎么使用离散后的结果数组来进行树状数组操作,计算出逆序数? 

如果数据不是很大,可以一个个插入到树状数组中,每插入一个数,统计比他小的数的个数,对应的逆序为 i- getsum(aa

[i]),其中i为当前已经插入的数的个数,getsum(aa[i])为比aa[i]小的数的个数,i- sum(aa[i]) 即比aa[i]大的个数,

即逆序的个数但如果数据比较大,就必须采用离散化方法。

【AC code】

//POJ.2299//Ultra-QuickSort#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=500010;#define ll long longstruct node{    int v,order;    friend bool operator<(const node &p,const node &q)    {        return p.v<q.v;    }}a[maxn];//输入部分int aa[maxn];//离散化后的数组int c[maxn];//树状数组int n;void init(){    memset(c,0,sizeof(c));}int getsum(int i){    int s=0;    while(i>0)    {        s+=c[i];        i-=i&-i;    }    return s;}void add(int i,int x){    while(i<=n)    {        c[i]+=x;        i+=i&-i;    }}int main(){    while(scanf("%d",&n)!=EOF)    {        if(n==0) break;        for(int i=1; i<=n; i++)        {            scanf("%d",&a[i].v);            a[i].order=i;        }        sort(a+1,a+n+1);        for(int i=1; i<=n; i++)        {            aa[a[i].order]=i;        }        init();        ll ans=0;        for(int i=1; i<=n; i++)        {            add(aa[i],1);            ans+=i-getsum(aa[i]);        }        printf("%lld\n",ans);    }}

【2 HDU.2492】

【题意】有两个人可以参加比赛,但是他们必须选一个裁判,并且这个裁判的能力值不能比这个人高,也不能比这个人低,求满足的方案数!对于每个人,只需要统计左边比他高,右边比他低的人数或者,统计左边比他低,右边比他高的人数,这两种选择的方案数之和就是整个的方案数。

【AC code】

//HDU.2492#include<cstdio>#include<cstring>#include<cmath>#include<cctype>#include<iostream>using namespace std;#define ll long longconst int maxn=100005;int a[maxn],b[maxn],c[maxn],d[maxn],e[maxn],f[maxn];int getInt(int &x){    return scanf("%d",&x);}int n;int low_bit(int x){    return x&(-x);}void update(int x,int v){   while(x<=maxn)   {       a[x]+=v;       x+=low_bit(x);   }}int get_sum(int x){    int sum=0;    while(x>0)    {        sum+=a[x];        x-=low_bit(x);    }    return sum;}int main(){    int tt;ll ans;    getInt(tt);    while(tt--)    {        getInt(n);        memset(a,0,sizeof(a));        ans=0;        for(int i=1;i<=n;i++)        {            getInt(b[i]);        }        for(int i=1;i<=n;i++)        {            update(b[i],1);            c[i]=get_sum(maxn)-get_sum(b[i]);  //左边有多少个数比自己大            d[i]=get_sum(b[i]-1);              //左边有多少个数比自己小        }        memset(a,0,sizeof(a));        for(int i=n;i>=1;i--)        {            update(b[i],1);            e[i]=get_sum(maxn)-get_sum(b[i]);   //右边有多少个数比自己大            f[i]=get_sum(b[i]-1);               //右边有多少个数比自己小        }        for(int i=1;i<=n;i++)        {            ans+=c[i]*f[i]+d[i]*e[i];        }        printf("%lld\n",ans);    }    return 0;}



1 0
原创粉丝点击