例题7 la 4329 http://acm.hust.edu.cn/vjudge/problem/13895
每个人有能力值, 一场比赛需要3个人, 要求下标中间的人作为裁判 , 且中间的人的能力值 要在左右两个人之间 ,问共能进行多少场比赛.
树状数组统计某个人前面有多少比他小的, 前大, 后小 后大, 情况等于 前面小* 后面大 或者前面大*后面小.
1 //#define txtout 2 //#define debug 3 #include<bits/stdc++.h> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 typedef long long LL; 7 const double pi=acos(-1.0); 8 const double eps=1e-8; 9 const int inf=0x3f3f3f3f; 10 const int M=1e5+10; 11 class One_Tree_Array { ///一维树状数组 12 static const int M=1e5+10; ///点的个数 13 typedef int typev; 14 typev a[M]; 15 int n; 16 public: 17 void init(int tn) { ///传入点数,点下标 1 开始 18 n=tn; 19 for(int i=0; i<=n; i++) a[i]=0; 20 } 21 int lowb(int t) { 22 return t&(-t); 23 } 24 void add(int i,typev v) { 25 for(; i<=n; a[i]+=v,i+=lowb(i)); 26 } 27 typev sum(int i) { 28 typev s=0; 29 for(; i>0; s+=a[i],i-=lowb(i)); 30 return s; 31 } 32 } tree; 33 int n; 34 int a[M]; 35 LL frontSmall[M]; 36 LL frontBig[M]; 37 LL backSmall[M]; 38 LL backBig[M]; 39 LL solve() { 40 int big=1e5; 41 tree.init(big); 42 for(int i=0;i<n;i++){ 43 frontSmall[i]=tree.sum(a[i]); 44 frontBig[i]=tree.sum(big)-tree.sum(a[i]); 45 tree.add(a[i],1); 46 } 47 tree.init(big); 48 for(int i=n-1;i>=0;i--){ 49 backSmall[i]=tree.sum(a[i]); 50 backBig[i]=tree.sum(big)-tree.sum(a[i]); 51 tree.add(a[i],1); 52 } 53 LL sum=0; 54 for(int i=0;i<n;i++){ 55 sum+=frontSmall[i]*backBig[i]; 56 sum+=frontBig[i]*backSmall[i]; 57 } 58 return sum; 59 } 60 int main() { 61 #ifdef txtout 62 freopen("in.txt","r",stdin); 63 freopen("out.txt","w",stdout); 64 #endif // txtout 65 int t; 66 while(~scanf("%d",&t)) { 67 while(t--) { 68 scanf("%d",&n); 69 for(int i=0; i<n; i++) { 70 scanf("%d",&a[i]); 71 } 72 printf("%lld\n",solve()); 73 } 74 } 75 return 0; 76 }