题目:
先分析此题:此题要求的是找到三个人,使得其住的地方是递增的,且当裁判的那个人的能力值在对决的两个人的能力值之间。
一开始想枚举对决的两个人,由于n比较大,所以枚举只能是其中一个,但是最后发现,这样的话,太难确定此人的对手和裁判了。
所以目光应该转向裁判,我们可以枚举裁判。只要知道裁判的左右比比其大的值就行了。
首先想到是的遍历,遍历肯定是能够达到我们想要的值的,但是复杂度高。我们必须在logn的时间内找到前面比其大的值。由于此题的能力值在20000之间,所以只要开个20000的数组当标志肯定是行的。对于当前的ai,想知道小于ai的值有多少个,也就是sum[ai - 1],这个不就是前缀和吗?至此我们知道使用树状数组就行了。
树状数组的介绍:http://www.cnblogs.com/justforgl/archive/2012/07/27/2612364.html
刘汝佳先生的书中介绍的应该更详细。更好懂一些。
在此总结目前我所知到得树状数组的用处:求某一段连续序列的和,且可以修改其中的元素。此时就可以使用树状数组.
//
// main.cpp
// LA 4329 - Ping pong 树状数组
//
// Created by XD on 15/8/21.
// Copyright (c) 2015年 XD. All rights reserved.
//
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
#define ll long long
using namespace std ;
const int maxn = 200000 +10 ;
int C[maxn] ;
int n ;
int lowerbit(int x)
{
return x&(-x) ;
}
//求和
int sum(int x)
{
int ret = 0 ;
while (x > 0 ) {
ret += C[x] ; x -= lowerbit(x) ;
}
return ret ;
}
//动态改变某个值,然后更新
void add(int x , int d)
{
while (x <= maxn) {
C[x] += d ;
x += lowerbit(x) ;
}
}
int c[maxn] ;
int m[maxn] ;
int arr[maxn] ;
int main() {
ll ans = 0 ;int T ;int d ;
scanf("%d" ,&T) ;
while (T--) {
ans = 0 ;
scanf("%d" ,&n) ;
memset(C, 0, sizeof(C)) ;
for (int i = 1; i <= n ; i++) {
scanf("%d" ,&d) ;
arr[i] = d ;
add(d, 1) ;
c[i] = sum(d-1) ;
m[i] = i -1 - c[i] ;
}
for (int i = 2; i <= n ; i++) {
int t = sum(arr[i]-1) ;
ans +=(c[i] * (n-1-t - m[i]) + (m[i] * (t-c[i]))) ;
}
printf("%lld\n" ,ans) ;
}
return 0;
}