这道题是树状数组的另一用法,用值去作为数组的下标。

具体思路:

input :

1
3 1 2 3
output:
1
先以其中一个数假设为a为中心,利用树状数组的优势求出这个数a左边比它自己大的数的个数,再求出这个数a的右边比它自己大的个数,分别记为lmin[a],lmax[a],rmin[a],rmax[a];然后结果就是sum+=lmin[i]*rmax[i]+rmin[i]*rmax[i];外层加上一个for循环就OK啦,还不明白么?看看下面的代码,再想想上面说的这段话,很容易理解滴。
还有,做这道题之后,我深刻地意识到,cin不能乱用啊,输入量大的时候,非常容易TLE,恐怖啊!以后注意点

 

#include<iostream> 
#define M 100001 
#define lowbit(x) x&(-x) 
using namespace std; 
 
int flag[100001],rank[100001],rmin[100001],rmax[100001],lmin[100001],lmax[100001]; 
int m; 
 
int add(int n) 

 while(n<=M)//注意这里的M是全部的,而不是m 
 { 
  flag[n]++; 
  n+=lowbit(n); 
 } 
 return 0

 
int subsum(int n) 

 int sum=0
 while(n>=1
 { 
  sum+=flag[n]; 
  n-=lowbit(n); 
 } 
 return sum; 

 
int main(void

 int n,i,j; 
 cin>>n; 
 while(n--) 
 { 
  _int64 sum=0
  scanf("%d",&m); 
  for(i=1;i<=m;i++) 
   scanf("%d",&rank[i]);//这里不可以用cin,因为输入量太大,用cin就TLE,输入量达到100000 
  for(i=1;i<=M;i++) 
   flag[i]=0;//初始化,注意要全数组初始化 
  for(i=1;i<=m;i++) 
  { 
   lmin[i]=subsum(rank[i]); 
   lmax[i]=i-lmin[i]-1
   add(rank[i]); 
  } 
  for(i=1;i<=M;i++) 
   flag[i]=0
  for(i=m,j=1;i>=1;i--,j++) 
  { 
   rmin[i]=subsum(rank[i]); 
   rmax[i]=j-1-rmin[i]; 
   add(rank[i]); 
  } 
 // for(i=1;i<m+1;i++) 
 //  cout<<lmin[i]<<"   "<<lmax[i]<<"   "<<rmin[i]<<"   "<<rmax[i]<<"   "<<endl; 
  for(i=1;i<=m;i++) 
   sum+=lmin[i]*rmax[i]+lmax[i]*rmin[i];//要考虑这里是会溢出的,因为左右如果都为50000,那么相乘就会int溢出 
  printf("%I64d\n",sum); 
 } 
 return 0

  
 
 
posted on 2011-04-23 20:46  cchun  阅读(161)  评论(0编辑  收藏  举报