hdu 5147(树状数组)

Sequence II

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1002    Accepted Submission(s): 408


Problem Description
Long long ago, there is a sequence A with length n. All numbers in this sequence is no smaller than 1 and no bigger than n, and all numbers are different in this sequence.
Please calculate how many quad (a,b,c,d) satisfy:
1. 1a<b<c<dn
2. Aa<Ab
3. Ac<Ad
 

 

Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,,An.

[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
 

 

Output
For each case output one line contains a integer,the number of quad.
 

 

Sample Input
1 5 1 3 2 4 5
 

 

Sample Output
4
 

 

Source
 
题意:找出一个长度为n的串里面有多少数字满足 Aa<Ab,Ac<Ad,a<b<c<d (a,b,c,d是下标)
题解:做过这个题之后一看就知道是树状数组统计了,我的想法是对每个 b 进行统计,首先是对b前面的数字进行统计,统计有多少个比它小的,这里可以利用树状数组的逆序模型进行统计。然后对于b后面的数字,我们可以统计有多少对 (c,d),这里的话从n-1对每个数进行统计比它大的有多少,然后如果要统计 b 后面有多少个比它大的数对,那么我们就可以利用保存后缀和的方式存下来就OK,最后里用乘法原理统计即可。l,r数组一定记得开_int64 ,不然会溢出。
解释一下这里的后缀,比如说 1 2 3 4 5
先统计 5 ,没有比他大的,所以r[5] = 0
然后是 4 ,5 比他大,所以 r[4] = 1
然后是 3 , 4 5比他大,所以 r[3]=2,加上后面已经出现的r[4],r[3]=r[3]+r[4] = 3
然后是 2 ,r[2]:(2,3)(2,4)(2,5) 加上 (3,4),(3,5),(4,5),所以r[2] = 6
最后是 1 , r[1]:(1,2)(1,3)(1,4)(1,5),加上r[3] 所以 r[1] = 10
我们是以 Ab 为基准的,所以每次统计的是 b 之前比比他小的,以及他后面所包含的二元组.所以每次的结果是 L[b]*R[b+1]
#include<stdio.h>
#include<iostream>
#include<string.h>
#include <stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 50005;
int n;
int c[N],a[N];
LL l[N],r[N];
int lowbit(int x)
{
    return x&-x;
}
void update(int idx,int v)
{
    for(int i=idx; i<=n; i+=lowbit(i))
    {
        c[i]+=v;
    }
}
int getsum(int idx)
{
    int sum = 0;
    for(int i=idx; i>0; i-=lowbit(i))
    {
        sum+=c[i];
    }
    return sum;
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        memset(c,0,sizeof(c));
        memset(l,0,sizeof(l));
        scanf("%d",&n);
        int cnt = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            update(a[i],1);
            l[i] = getsum(a[i]-1); ///a[i]之前小于a[i]的数
        }
        memset(c,0,sizeof(c));
        memset(r,0,sizeof(r));
        for(int i=n; i>=1; i--)
        {
            update(a[i],1);
            r[i]=n-i-getsum(a[i]-1);///统计每个数后面比它大的
            r[i]+=r[i+1]; ///记录后缀和
        }
        LL ans = 0;
        for(int i=2;i<n-1;i++){
            ans+=l[i]*r[i+1];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2016-07-14 19:12  樱花庄的龙之介大人  阅读(174)  评论(0编辑  收藏  举报