UVALive 4329 Ping pong(树状数组)
题目链接:UVALive 4329
题意:
一条大街依次住着n个乒乓球爱好者,每个人都有一个不同的技能值ai。举行每场比赛需要3个人:两名选手和一名裁判,且要求裁判住在两名选手之间,技能值也在两名选手之间。问一共能组织多少种比赛。
分析:
考虑第i个人当裁判(从0开始编号)的时候,假设a0~ai-1中有Li个比ai小的,则i-Li个比ai打的,ai+1~an-1中有Ri个比ai小的,则n-(i+1)-Ri个比ai大的。第i个人当裁判就有Li*(n-i-1-Ri) + (i-Li)*Ri种比赛。问题就转变成枚举i求Li和Ri。
从左往右扫描所有ai,cnt[ai]表示技能值为ai的人数,扫到第i个Li=cnt[1]+cnt[2]+cnt[3]+...+cnt[ai - 1],然后cnt[ai]++,同理,Ri=cnt[1]+cnt[2]+cnt[3]+...+cnt[ai - 1],但cnt[ai]--,问题需要统计cnt[1]~cnt[ai - 1]的值且需更新cnt[ai],树状数组能较好的满足操作需求。
代码实现:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100000 + 5;
int L[N], R[N], maxa, a[N];
int lowbit(int x)
{
return x & (-x);
}
void add(int *A, int x, int d)
{
for (int i = x; i <= maxa; i += lowbit(i))
A[i] += d;
}
int sum(int *A, int x)
{
int ret = 0;
for (int i = x; i; i -= lowbit(i))
ret += A[i];
return ret;
}
int main()
{
int T, n;
LL ans;
scanf("%d", &T);
while (T--) {
maxa = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
if (a[i] > maxa) maxa = a[i];
}
memset(L, 0, sizeof(L));
memset(R, 0, sizeof(R));
for (int i = 0; i < n; i++)
add(R, a[i], 1);
ans = 0LL;
for (int i = 0; i < n; i++) {
int lcnt = sum(L, a[i]-1);
add(L, a[i], 1);
int rcnt = sum(R, a[i]-1);
add(R, a[i], -1);
ans += (LL)lcnt*(n-i-1-rcnt) + (LL)rcnt*(i-lcnt);
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号