poj_2299_Ultra-QuickSort

来源:互联网 发布:第四类接触知乎 编辑:程序博客网 时间:2024/06/01 13:55

线段树,树状数组,归并排序入门好题.

在此给出三种算法的入门讲解.

题目大意:

给出一个序列,求这个序列的逆序数有多少.意思就是给一个序列,对于序列中的每一位,前面有多少位大于它的数.求这些个数的合.这个序列一共最多有n < 500,000个数.


解题思路:

基本问题就是统计每一位前面大于它的数.因为每个数0 ≤ a[i] ≤ 999,999,999 ,而总数只有500,000,所以如果用线段树或树状数组做需要排序后离散化.

离散化:

对于一组十个数的离散化:

Number

1

10

100

200

45

78

10

63

85

900

Id

1

2

3

4

5

6

7

8

9

10




先对数组排序由ID抽象出新的序列数字,得出新的个数时要注意,当原个数相同时,新个数也要相同,同时下一个数的值等于它的位置N:

New n

1

2

2

4

5

6

7

8

9

10

Old n

1

10

10

45

63

78

85

100

200

900

Id

1

2

7

5

8

6

9

3

4

10






原序列就转化为:

Number

1

10

100

200

45

78

10

63

85

900

New n

1

2

8

9

4

6

2

5

7

10




由此方法可将这道题数据范围缩小至500000;

离散化结束后就可以求每一个数前面比其小的数的个数了.

源代码-树状数组:

#include <iostream>#include <cstdio>#include <cstring>#include <climits>using namespace std;const int N=500010;typedef struct _data{int id;int num;}data;int n;int b[N],c[N];long long ans;data a[N];int cmp(const void *a,const void *b){return ((data *)a)->num - ((data *)b)->num;}void init(){ans=0;memset(b,0,sizeof(b));memset(c,0,sizeof(c));int i;for(i=1;i<=n;i++)scanf("%d",&a[i].num),a[i].id=i;qsort(a+1,n,sizeof(a[0]),cmp);b[a[1].id]=1;for(i=2;i<=n;i++)if(a[i].num!=a[i-1].num)b[a[i].id]=i;elseb[a[i].id]=b[a[i-1].id];}inline int lowbit(int x){return x&(-x);}void updata(int x,int k){for(int i=x;i<=n;i+=lowbit(i))c[i]+=k;}int getsum(int x){int sum=0;for(int i=x;i>0;i-=lowbit(i))sum+=c[i];return sum;}int main(){while(scanf("%d",&n),n){init();for(int i=1;i<=n;i++){updata(b[i],1);ans+=(getsum(n)-getsum(b[i]));}printf("%lld\n",ans);}return 0;}


源代码-线段树:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define ROOT 1,n,1#define LSON l,m,rt<<1#define RSON m+1,r,rt<<1|1const int N=500010;typedef struct _sArray{int x,id;}sArray;int n,a[N],c[N<<2];sArray b[N];int cmp(const void *a,const void *b){return ((sArray *)a)->x - ((sArray *)b)->x;}inline void pushUp(int rt){c[rt]=c[rt<<1]+c[rt<<1|1];}void build(int l,int r,int rt){c[rt]=0;if(l==r)return ;int m=(l+r)>>1;build(LSON);build(RSON);pushUp(rt);}void init(){int i;for(i=1;i<=n;i++){scanf("%d",&b[i].x);b[i].id=i;}qsort(b+1,n,sizeof(b[0]),cmp);a[b[1].id]=1;for(i=2;i<=n;i++){if(b[i-1].x==b[i].x)a[b[i].id]=a[b[i-1].id];elsea[b[i].id]=i;}memset(c,0,sizeof(c));build(ROOT);}void upData(int q,int l,int r,int rt){if(l==r){c[rt]++;return ;}int m=(l+r)>>1;if(q<=m)upData(q,LSON);elseupData(q,RSON);pushUp(rt);}long long getSum(int L,int R,int l,int r,int rt){if(L<=l&&r<=R)return c[rt];int m=(l+r)>>1;long long ret=0;if(L<=m)ret+=getSum(L,R,LSON);if(R>m)ret+=getSum(L,R,RSON);return ret;}void word(){int i;long long ans=0;for(i=1;i<=n;i++){upData(a[i],ROOT);ans+=getSum(a[i]+1,n,ROOT);}printf("%lld\n",ans);}int main(){while(scanf("%d",&n),n){init();word();}return 0;}



原创粉丝点击