LA 4329 - Ping pong 树状数组

题目:

先分析此题:此题要求的是找到三个人,使得其住的地方是递增的,且当裁判的那个人的能力值在对决的两个人的能力值之间。

一开始想枚举对决的两个人,由于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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值