身为弱菜,觉得有必要偶尔写一写题解,加深记忆。
刚开始完全不明白为什么要树状数组,百度了一发,随手点了几个,都是归并写的,便没有看了,果断请教人去了。
这道题大概意思就是求逆序数。
所谓逆序,比如:1,2 是正序,2,1 就是逆序。
拿样例说话:9 1 0 5 4 9 1是一对逆序数,依次9 0, 9 1 ,9 5, 9 4,这里就有4个逆序数,然后1只有一个逆序,即1 0,。
接下来是 5 4,所以答案是6.
这样下来,抛开数据范围,直接暴力O(N^2)的复杂度。然后,数据范围太大,必然T。然后,我们可以换一个角度想,必然 4 3 2 1,不难看出4的逆序是3。若3在4以前就出现,那么4的逆序就成了2,所以,我们只需要计算当求p[ i ]的逆序时,用它的全逆序减去它前面已经出现的比它小的数字个数就行了。又因为 ai 的范围比较大, 所以可以考虑加个离散化,当然,也可以不加,这里就不谈不用离散化的了,其实两个都差不了多少。
代码如下(写得略挫,勿喷):
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL __int64
using namespace std;
struct NODE
{
int pos;
int x;//离散化用
LL val;
bool operator < (const NODE &X) const
{
return val<X.val;
}
}p[500500];
int c[500500];
int n;
LL ans;
bool cmp(NODE A,NODE B)
{
return A.pos<B.pos;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int val)
{
while(x<=n)
{
c[x]+=val;
x+=lowbit(x);
}
}
int sum(int x)
{
int rt=0;
while(x)
{
rt+=c[x];
x-=lowbit(x);
}
return rt;
}
int main()
{
while(~scanf("%d",&n),n)
{
for(int i=1;i<=n;i++)
{
scanf("%I64d",&p[i].val);
p[i].pos=i;
}
for(int i=0;i<=n;i++)
c[i]=0;
sort(p+1,p+n+1);
ans=0;
for(int i=1;i<=n;i++)//求全逆序,顺便离散化。
{
ans=ans+i-1;
p[i].x=i;
}
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++)
{
ans=ans-sum(p[i].x);
add(p[i].x,1);
}
printf("%I64d\n",ans);
}
return 0;
}