POJ3928

/*
采用树状数组加速程序

思路是,分数无关,先排序,把index拿出来。满足条件的的 a b c编号必须是a < b < c或者 a >b > c
所以对编号数组从左到右和从右到左扫描,计算出每个编号左边比自己小的个数,右边比自己大的个数,乘起来就是结果,当然还要加上反的情况。
基本上可以算是O(n)把
*/

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;

#define MAXN 100010
#define MAXP 20010

int Bit[MAXN];
int rank[MAXP];
int dx[MAXN];
int Lleft[MAXP],Rright[MAXP];
int T,N;

int lowBit(int x)
{
	return x&(-x);
}

void update(int x,int c)
{
	for(int i=x;i<=N;i+=lowBit(i))
	{
		Bit[i]+=c;
	}
}

int getsum(int x)
{
	int ans = 0;
	for(int i=x;i>0;i-=lowBit(i))
	{
		ans += Bit[i];
	}
	return ans;
}

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&N);
		for(int i=0;i<N;i++)
		{
			scanf("%d",&rank[i]);
			dx[rank[i]] = i;	
		}
		sort(rank,rank+N);
		for(int i=0;i<N;i++)
		{
			rank[i] = dx[rank[i]]+1;
		}

		//for(int i=0;i<MAXN;++i) Bit[i] = 0;
		memset(Bit,0,sizeof(int)*MAXN);
		for(int i=0;i<N;++i)
		{
			Lleft[i] = Rright[i] = 0;
		}
		for(int i=0;i<N;i++)
		{
			Lleft[i] = getsum(rank[i]);
			update(rank[i],1);
		}

		//for(int i=0;i<MAXN;++i) Bit[i] = 0;
		memset(Bit,0,sizeof(int)*MAXN);
		for(int i=N-1;i>=0;--i)
		{
			Rright[i] = getsum(rank[i]);
			update(rank[i],1);
		}
		long long ans = 0;
		for(int i=0;i<N;++i)
		{
			ans += Lleft[i]*(N-1-i-Rright[i])+(i-Lleft[i])*Rright[i];
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  

编辑器加载中...

posted @ 2012-03-30 12:03  AC2012  阅读(395)  评论(1编辑  收藏  举报