突然想起树状数组了,因为突然想起之前从来没A掉的那个树状数组求逆序数的题,大概意思就是求一个数组用冒泡排序排序后的交换次数,因为数据量为5万,所以O(n*n)的冒泡模拟肯定是超时的,所以题目的解法可以有两种,一种是归并排序,归并排序的一个应用正是求逆序数,而另一个就是树状数组了。
思想就是通过将数一个一个的插入到树状数组中,每次统计这个数之前比它大的数的sum值,所以这里树状数组里每次add更新的是比这个数大的数的个数而不是数的值。因为数据里面给的范围是99999999,特别大,所以说需要离散化一下。一开始看别的人的本来我也讨厌离散化的,可惜看着数据量觉得不离散化好像过的费劲(现在看看离散化也没太烦)。为啥需要离散化呢?比如给你5个数,
99999999,1,2,3,4.
这些数里,第一个数需要用的树状数组为c[99999999]这么大,就是这个意思,开不了这么大-_-#,那么我们可以用一个结构体node,里面有俩值,一个存输入的值,一个存这个值的下标:
struct node
{
int data; //存值
int pos;//存下标
};
node p[510000];//离散化的数组
那么我们每次输入的时候就输入到p[i].data,并且p[i].pos = i;
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&p[i].data);
p[i].pos = i;
}
然后我们将这个离散化的数组按照 数值 从小到大排序。
bool cmp(node a,node b)
{
return a.data < b.data;
}
sort(p+1,p+n+1,cmp);
再用一个数组a[510000]来存储排序后的离散化数组
for(int i = 1 ; i <= n ; i++)
a[ p[i].pos ] = i;
开始的时候,大家到这一步可能有点蒙,好好想想,其实就是这个意思:你要求的数组一共不超过500000个,但是如果用树状数组来求,你就需要最大c[9999999]这么大的,所以我们就将99999999存在p[n].data里面,这时候n最大就是500000吧,所以达到减少内存的目的,这时候上面我给的样例就是
p[i].data: 1,2,3,4,99999
p[i].pos: 2,3,4,5,1
a[ p[i].pos ]: 1,2,3,4,5
也就是 a[2] = 1,a[3] = 2,a[4] = 3,a[5] = 4,a[1] = 5;
接下来就是将每个数插入到树状数组中,并且每次往add里增加的数并不是第i个数的数值data,而是+1,也就是说每次sum统计的是比这数小的数,然后我们用这个i-sum(a[i])得到的就是这个数的逆序数啦
我们将答案加上每个数的逆序数即可
for(int i = 1 ; i <= n ; i++)
{
add(a[i],1);
ans += i-sum(a[i]);
}
完整的程序:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
using namespace std;
struct node
{
int data; //存值
int pos;//存下标
</span>
};
long long ans;
node p[510000];<span style="white-space:pre"> //离散化的数组
int c[510000];<span style="white-space:pre"> //树状数组
int a[510000],n;<span style="white-space:pre"> //存离散化数组的a数组
bool cmp(node a,node b)
{
return a.data < b.data;
}
int lowbit(int x)
{
return x&-x;
}
void add(int i,int x)
{
while(i <= n)
{
c[i] += x;
i += lowbit(i);
}
}
int sum(int i)
{
int ans = 0;
while(i > 0)
{
ans += c[i];
i -= lowbit(i);
}
return ans;
}
int main(int argc, char *argv[])
{
while(scanf("%d",&n)!=EOF)
{
if(n == 0)break;
ans = 0;
memset(c,0,sizeof(c));
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&p[i].data);
p[i].pos = i;
}
sort(p+1,p+n+1,cmp);
for(int i = 1; i <= n ; i++)
a[p[i].pos] = i;
for(int i = 1 ; i <= n ; i++)
{
add(a[i],1);
ans += i-sum(a[i]);
}
printf("%lld\n",ans);
}
return 0;
}
文笔也不好,要是有啥不对的大家一定告诉我T_T (500多MS过的,弱爆了)