题目信息:点击打开链接 求逆序数
树状数组求逆序数就是不停的向树状数组中插入值,插入的同时更新树状数组,并统计逆序数的个数,在代码中会详细解释;另外大家会发现这种方法很类似于hash标记,即先开一个hash数组(和题上数据范围一样大),然后插入值a,然后标记hash[a]为1,假如a是第5个插入的,那a的逆序数就是5-get_sum(C[4])(C为树状数组),但是这道题的数据范围为10^9,根本开不了这麽大的数组,那就讲到了 离散化处理,假如有这样一组数5 3 2 7 999999999,如果直接哈希开数组要开到hash[999999999];但这在实际中是开不到的,也完全没必要开这麽大,我们求得是逆序数,也就是只和每个数的相对大小有关系,那3 2 1 4 5和上面那组数的逆序数是一样的,离散化就完成两个数组之间的转化,转化之后hash数组只需要hash[5]就行。
代码如下:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
//用于离散化处理
struct node{
int v;//数值
int w;//出现位置
}s[1000005];
long long c[1000005],tree[1000005];
int lowbit(int x)
{
return x&(-x);
}
void insert(int x,int y,int n)
{
while(x<=n)
{
tree[x]+=y;
x+=lowbit(x);
}
}
int get_sum(int x)
{
int sum=0;
while(x>0)
{
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
bool cmp(node s1,node s2)
{
if(s1.v!=s2.v)
return s1.v<s2.v;
return s1.w<s2.w;//由于一组数据中有相同数据,故需稳定排序
}
int main()
{
int T,N,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for(i=1;i<=N;i++)
{
scanf("%lld",&s[i].v);
s[i].w=i;
}
sort(s+1,s+N+1,cmp);//稳定排序
for(i=1;i<=N;i++)//离散化处理
c[s[i].w]=i;
memset(tree,0,sizeof(tree));//初始化树状数组
long long ans=0;
for(i=1;i<=N;i++)
{
insert(c[i],1,N);
ans+=(i-get_sum(c[i]));//求逆序数,当前插入次数i-当前插入位置前面的数总个数get_sum(c[i]);
}
printf("%lld\n",ans);
}
}
另外前面的博客也说道归并排序求逆序数,代码如下:
#include<stdio.h>
#include<string.h>
#define N 1000005
long long cnt=0;
int a[N],c[N];
//归并排序的合并操作
int merge(int a[],int first,int mid,int last,int c[])
{
int i=first,j=mid+1;
int m=mid,n=last;
int k=0;
while(i<=m||j<=n)
{
if(j>n||(i<=m&&a[i]<=a[j]))
c[k++]=a[i++];
else
{c[k++]=a[j++];cnt+=(m-i+1);}
}
for(i=0;i<k;i++)
a[first+i]=c[i];
}
//归并排序的递归分解和合并
void merge_sort(int a[],int first,int last,int c[])
{
if(first<last)
{
int mid=(first+last)/2;
merge_sort(a,first,mid,c);
merge_sort(a,mid+1,last,c);
merge(a,first,mid,last,c);
}
}
int main()
{
int T,M,i;
scanf("%d",&T);
while(T--)
{
scanf("%d",&M);
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
cnt=0;
for(i=0;i<M;i++)
scanf("%d",&a[i]);
merge_sort(a,0,M-1,c);
printf("%lld\n",cnt);
}
}
同样的题,树状数组写的跑了1200ms,归并排序才跑600ms不到。。。