uvalive 4329 Ping Pong(树状数组)

来源:互联网 发布:淘宝账号为什么会被盗 编辑:程序博客网 时间:2024/06/01 18:17

题目链接:https://vjudge.net/problem/UVALive-4329

题意:

一条直线上有n个乒乓选手,每个人有一个技能值ai,他们之间需要切磋,需要一个裁判,裁判的技能值要在两个人之间,问一共有多少个个方案。裁判不同或者选手不同都可以看做是不同的方案。

思路:

参照白书。考虑第i个人当裁判,设a[1]到a[i-1]有c[i]个比a[i]小,那么有(i-1)-c[i]个比a[i]大,a[i+1]到a[i]有d[i]个比a[i]小,那么有(n-i)-d[i]个比a[i]大,那么得到公式

ans=c[i](nid[i])+(ic[i]1)d[i]

做法:

使用线段树或者树状数组。
使用树状数组时:
求b[](此处的b[]相当于上文的c[]),n次add,将大于a[i]的点加上1,每次求下标i左边小于a[i]的个数,用b[i]来记录。
求d[],倒着枚举(因为求的是在i的右边小于a[i]的个数,如果正着枚举,到i时,树状数组里已经记录了前i个中比a[i]小的个数,这是不对的),其他的和求b[]同理。
最后O(n)求和就可以得到答案。

#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int maxn = 100000 + 100;int t, n, a[maxn], c[maxn], b[maxn], d[maxn];inline int lowbit(int x){    return x&-x;}void add(int x){    while(x<=maxn){        c[x] += 1;        x += lowbit(x);    }}int sum(int x){    int ret = 0;    while(x > 0){        ret += c[x];        x -= lowbit(x);    }    return ret;}int main(){     cin>>t;    while(t--){        cin>>n;        for(int i=1; i<=n; ++i) cin>>a[i];        memset(c, 0, sizeof(c));        for(int i=1; i<=n; ++i){            add(a[i]);            b[i] = sum(a[i]-1);        }        memset(c, 0, sizeof(c));        for(int i=n; i>0; --i){            add(a[i]);            d[i] = sum(a[i]-1);        }        long long ans = 0;        for(int i=1; i<n; ++i){            ans += (long long)b[i]*(n-i-d[i]) + (long long)(i-b[i]-1)*d[i];         }        cout<<ans<<endl;    }    return 0;}

使用线段树:
按照能力值建树,即0到100000,每次更新把区间[a[i], 100000]加一,正着枚举a[i],可以得到c[],同理重新建树,逆着枚举a[i]得到d[i]。