HDU 2492 Ping pong(树状数组)

N(3<=N<=20000) ping pong players live along a west-east street(consider the street as a line segment).

Each player has a unique skill rank. To improve their skill rank, they often compete with each other. If two players want to compete, they must choose a referee among other ping pong players and hold the game in the referee’s house. For some reason, the contestants can’t choose a referee whose skill rank is higher or lower than both of theirs.

The contestants have to walk to the referee’s house, and because they are lazy, they want to make their total walking distance no more than the distance between their houses. Of course all players live in different houses and the position of their houses are all different. If the referee or any of the two contestants is different, we call two games different. Now is the problem: how many different games can be held in this ping pong street?
Input
The first line of the input contains an integer T(1<=T<=20), indicating the number of test cases, followed by T lines each of which describes a test case.

Every test case consists of N + 1 integers. The first integer is N, the number of players. Then N distinct integers a1, a2 … aN follow, indicating the skill rank of each player, in the order of west to east. (1 <= ai <= 100000, i = 1 … N).
Output
For each test case, output a single line contains an integer, the total number of different games.
Sample Input
1
3 1 2 3
Sample Output
1

题意: 有n个人打乒乓球,每个人有一个技能值,现在两个人比赛需要一个水平在两人之间,位置也在两人之间的人做裁判,问有共有可以分出多少种不同的比赛。只要三人的技能值相同即算同一种比赛。如123和321。每个人的位置为其下标i值。

利用树状数组在输入时更新当第pos个人出现时,该人左边技能值小于和大于他的人数,树状数组下标表示技能值大小,内部存储在该水平值下有几个人,利用树状数组前缀和的性质可以快速得到某个人出现时小于他的人数和大于他的人数,因为pos是分先后出现的,在输入的同时更新和查询树状数组,并记录人数,这样每次查询到的都是保证技能值统一大于或小于这个人的,并且一定是该人出现之前的才出现的位序

然后清空树状数组,倒着遍历一遍输入值,重新统计该人右边有多少技能值大于和小于自己的。同上。

最后遍历所有人的左右人数计数,对于一个人做裁判的次数,即该人左边比其小的人数 乘 该人右边比起打的人数,然后反过来再乘一次,求和,即该人所有的裁判场次。

注意树状数组的更新,上限不是人数n,而是最大技能值,否则明显无法更新完全。

#include<bits/stdc++.h>
#define LL long long
const int maxn=100005;
const int inf=0x3f3f3f3f;
using namespace std;
LL tree[maxn],lowl[20004],lowr[20004],highl[20004],highr[20004];
int n,t;
struct node
{
    int val,pos;
} a[20004];
int lowbit(int x)
{
    return x&(-x);
}
void update(int x)
{
    while(x<=maxn)///注意这里的上限是最大的技能值,而不是人数,树状数组记录技能值的人数,下标表示技能值
    {
        tree[x]++;
        x+=lowbit(x);
    }
}
int query(int x)
{
    LL sum=0;
    while(x>0)
    {
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
bool cmp(node a,node b)
{
    return a.pos>b.pos;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof tree);
        memset(lowr,0,sizeof lowr);
        memset(lowl,0,sizeof lowl);
        memset(highl,0,sizeof highl);
        memset(highr,0,sizeof highr);
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i].val);
            a[i].pos=i;
            update(a[i].val);
            lowl[a[i].pos]+=query(a[i].val-1);
            highl[a[i].pos]+=i-query(a[i].val);
        }
        sort(a+1,a+1+n,cmp);
        memset(tree,0,sizeof tree);
        for(int i=1; i<=n; i++)
        {
            update(a[i].val);
            lowr[a[i].pos]+=query(a[i].val-1);
            highr[a[i].pos]+=i-query(a[i].val);
        }
//        for(int i=1; i<=n; i++)printf("i=%d   highl=%lld  highr=%lld  lowl=%lld  lowr=%lld
",i,highl[i],highr[i],lowl[i],lowr[i]);
        LL ans=0;
        for(int i=1; i<=n; i++)
            ans+=(lowl[i]*highr[i])+(lowr[i]*highl[i]);
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/kuronekonano/p/11135788.html