-----hoj 2275 Number sequence(树状数组)

Number sequence

Source : SCU Programming Contest 2006 Final
Time limit : 1 sec Memory limit : 64 M

Given a number sequence which has N element(s), please calculate the number of different collocation for three number Ai, Aj, Ak, which satisfy that Ai < Aj > Ak and i < j < k.
Input
The first line is an integer N (N <= 50000). The second line contains N integer(s): A1, A2, …, An(0 <= Ai <= 32768).
Output
There is only one number, which is the the number of different collocation.
Sample Input 5
1 2 3 4 1

Sample Output 6
解题思路:按照题目的意思,求的是一个数组里面,每一个数的左边比它小的数的个数,乘以右边比它小的数的个数,然后把所以数求得的数据相加就是所得答案
当然这道题可以用暴力,就是把每个数的左边比它小的数的个数,和右边比它小的数的个数相乘,然后累加,思路很简单,但是肯定会超时,用树状数组的话就会巧妙很多…反正我觉得超级神奇…发明树状数组的人..真的是超级厉害的呀…
主要的想法就是用每个元素作为树状数组对应的下标,比如data[1]=5,则data[1]对应的树状数组的下标就是5,( c[5] );
然后还有一个很重要的就是一边输入一边录入,也就是说,是有顺序之分的,从i=1,开始录入的时候,有一个数的左边的数总是比它先录入,如果从i=n,开始录入,就有一个数右边的数总是比它先录入,这样就保证了求当前输入的数的左边比它小的数的个数的时候,不会出现它右边的数(它右边比它小的数)….求右边比它小的数也同理;树状数组的下标恰好又是从小到大的,因此data[i]左边的比它小的数的个数( 用lefts[i]记录每个date[i]的左边比它小的数的个数),就是query( data[i]-1 ),即树状数组的前data[i]-1项和;右边同理….从i=n开始录入即可,当然要把tree[i]清空

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn=50010;
int tree[maxn];
int lefts[maxn];
int data[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void update(int pos)
{
    while(pos<=maxn)
    {
        tree[pos]++;
        pos+=lowbit(pos);
    }
}
int query(int k)
{
    int sum=0;
    while(k>0)
    {
        sum+=tree[k];
        k-=lowbit(k);
    }
    return sum;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(tree,0,sizeof(tree));
        for(int i=1;i<=n;i++)///一边输入数据,一边把data[i]作为树状数组的下标     
        {
             scanf("%d",&data[i]);
            lefts[i]=query(data[i]-1);///lefts[i]记录第i个数的左边比它小的数的个数,
                                     ///因为data[i]是按照顺序先后录入的,所以当前的树状数组只存在当前录入的数,和比它早录入的数,即它左边的数
                                     ///因此求data[i]左边比它小的数的和就应该是query(data[i]-1)
            update(data[i]);///这个数已经录入了,所以在树状数组这个数代表的下标处加上1
        }
        memset(tree,0,sizeof(tree));
        long long res=0;
        for(int i=n;i>0;i--)///从最右边的数开始录入
                           ///query(data[i]-1)求的是这个数右边比它小的数
        {
            res+=lefts[i]*query(data[i]-1);
            update(data[i]);
        }
        printf("%lld\n",res);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值