树状数组---逆序类题目

来源:互联网 发布:sql server和mysql区别 编辑:程序博客网 时间:2024/04/28 15:48

1. POJ 2299 Ultra-QuickSort(树状数组逆序+离散化)

题目链接:http://poj.org/problem?id=2299

题意: 给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列?

题解:其实就是求逆序对的数量。可以用树状数组来求。虽然数的大小为 999,999,999,但是数的规模只有500,000,所以可以对数据进行离散化,之后就可以用树状数组来求了。

代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int MAX=500000+5;typedef long long LL;int bit[MAX];int a[MAX];int tmp[MAX];int N;int sum(int x){    int sum=0;    while(x>0)    {        sum+=bit[x];        x-=(x&(-x));    }    return sum;}void add(int x,int value){    while(x<=N)    {        bit[x]+=value;        x+=(x&(-x));    }}int main(){    int n;    while(scanf("%d",&n)&&n)    {        memset(bit,0,sizeof(bit));        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            tmp[i]=a[i];        }        N=n;        sort(tmp,tmp+n);        for(int i=0;i<n;i++)        {            a[i]=lower_bound(tmp,tmp+n,a[i])-tmp+1;        }        LL ans=0;        for(int i=n-1;i>=0;i--)        {            ans=ans+sum(a[i]);            add(a[i],1);        }        cout<<ans<<endl;    }    return 0;}

2.HDU 1394 Minimum Inversion Number(树状数组逆序)

题目链接:点击打开链接

题意:给定一个序列,对该序列的n种排列(排列如下)的每种排列的逆序数求最大值:

a1, a2, ..., an-1, an  

a2, a3, ..., an, a1  

a3, a4, ..., an, a1, a2 

 ...  

an, a1, a2, ..., an-1 

题解:

我们可以分为n步,每次都将第一个元素移动到最后一个,这样原来的逆序对变为顺序对,原来的顺序对变为逆序对,所以逆序对减少的数量为(比他小的数的个数)减去(比他大的数的个数),即cnt-(n-1-cnt)=2*cnt-n+1,cnt为比当前数小的数,cnt可以用树状数组求出,但是因为每次操作的都是第一个数,并且数只有1-n,所以cnt就等于a[i]-1。cnt-(n-1-cnt)=2*cnt-n+1=2*a[i]-n-1。进行n步求出逆序对减少的数量的最大值用总的逆序对数减去这个值即可。

代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>using namespace std;const int MAX=5000+5;const int INF=0x3f3f3f3f;typedef long long LL;int a[MAX];int rs[MAX];int bit[MAX];int N;int sum(int x){    int s=0;    while(x>0)    {        s+=bit[x];        x-=(x&(-x));    }    return s;}void add(int x,int v){    while(x<=N)    {        bit[x]+=v;        x+=(x&(-x));    }}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        memset(bit,0,sizeof(bit));        N=n;        int tol=0;        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            a[i]++;            tol+=sum(N)-sum(a[i]);            add(a[i],1);        }        int mmax=0;        int cur=0;        for(int i=0;i<n-1;i++)        {           /* int cnt=sum(a[i]-1);            cur+=cnt-(n-1-cnt);*/            cur+=2*a[i]-n-1;            mmax=max(mmax,cur);        }        printf("%d\n",tol-mmax);    }    return 0;}


0 0