LA4329 Ping pong 树状数组

题意:
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个能力值a[i]。
每场比赛需要三个人:两名选手,一名裁判。他们有个奇怪的约定,裁判必须住在两名选手之间,而裁判的能力值也必须在两名选手之间。
问一共能组织多少种比赛。

分析:
考虑第i个人,假设a1到ai-1中有ci个比ai小,那么就有(i-1)-ci个比ai大;
同理,如果ai+1到an中有di个比ai小,那么就有(n-i)-di个比ai大。
i当裁判就有:ci * (n-i-di) + (i-1-ci)*di种比赛。

然后问题就转化为了计算数组c和数组d。这样的话就很容易想到使用树状数组去计算前缀和。
 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<set>
 7 #include<map>
 8 #include<vector>
 9 #include<cstring>
10 #include<stack>
11 #include<cmath>
12 #include<queue>
13 #include <bits/stdc++.h>
14 using namespace std;
15 #define INF 0x3f3f3f3f
16 #define ll long long
17 #define clc(a,b) memset(a,b,sizeof(a))
18 
19 inline int lowbit(int x)
20 {
21     return x&-x;
22 }
23 
24 struct bit
25 {
26     int n;
27     vector<int>C;
28 
29     void resise(int n)
30     {
31         this->n=n;
32         C.resize(n);
33     }
34     void clear()
35     {
36         fill(C.begin(),C.end(),0);
37     }
38     int sum(int x)
39     {
40         int ret=0;
41         while(x>0)
42         {
43             ret+=C[x];
44             x-=lowbit(x);
45         }
46         return ret;
47     }
48     void add(int x,int d)
49     {
50         while(x<=n)
51         {
52             C[x]+=d;
53             x+=lowbit(x);
54         }
55     }
56 };
57 
58 const int maxn=20000+5;
59 int n,a[maxn],c[maxn],d[maxn];
60 
61 bit f;
62 
63 int main()
64 {
65     int t;
66     scanf("%d",&t);
67     while(t--)
68     {
69         scanf("%d",&n);
70         int maxa=0;
71         for(int i=1; i<=n; i++)
72         {
73             scanf("%d",&a[i]);
74             maxa=max(maxa,a[i]);
75         }
76         f.resise(maxa);
77         f.clear();
78         for(int i=1; i<=n; i++)
79         {
80             f.add(a[i],1);
81             c[i]=f.sum(a[i]-1);
82         }
83         f.clear();
84         for(int i=n; i>=1; i--)
85         {
86             f.add(a[i],1);
87             d[i]=f.sum(a[i]-1);
88         }
89         ll ans=0;
90         for(int i=1; i<=n; i++)
91             ans+=(ll)c[i]*(n-i-d[i])+(ll)d[i]*(i-c[i]-1);
92         printf("%lld\n",ans);
93     }
94     return 0;
95 }
View Code

 

转载于:https://www.cnblogs.com/ITUPC/p/5189309.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值