树状数组

1、LA 4329 Ping pong

  题意:若干个乒乓球选手住在一条街上,每两个人可以选择一个居住在他们中间的且乒乓球段位在他们中间的人作为裁判,来进行一场比赛。问可以进行多少种不同的比赛。

  思路:找出a[i]左侧比a[i]段位低的人数,a[i]右侧比a[i]段位第的人数,则以a[i]作为裁判的比赛数目为L[i]*(n-i-R[i])+(i-1-L[i])*R[i].以树状数组来求段位在0~a[i]-1的人数。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int maxnum, n;
 6 const int maxn = 20100;
 7 const int maxv = 100100;
 8 int a[maxn];
 9 int b[maxv];//树状数组
10 int L[maxv];//表示在a[i]左侧比a[i]小的个数
11 int R[maxv];//表示在a[i]右侧比a[i]小的个数
12 int lowbit(int x)
13 {//得到x二进制表示中位数最低的1
14     return (x&(-x));
15 }
16 int Query(int k)
17 {//求前k个数的和,b[]为树状数组
18     int res = 0;
19     while (k)
20     {
21         res += b[k];
22         k -= lowbit(k);
23     }
24     return res;
25 }
26 void Update(int x, int k)
27 {//第x位加上k
28     while (x <= maxnum)
29     {
30         b[x] += k;
31         x +=lowbit(x);
32     }
33 }
34 int main()
35 {
36     int T;
37     scanf("%d", &T);
38     while (T--)
39     {
40         scanf("%d", &n);
41         maxnum = 0;
42         for (int i = 1; i <= n; i++)
43         {
44             scanf("%d", &a[i]);
45             maxnum = max(maxnum, a[i]);
46         }
47         memset(b, 0, sizeof(b));
48         for (int i = 1; i <= n; i++)
49         {
50             L[i] = Query(a[i] - 1);//询问在a[i]左侧比a[i]小的个数
51             Update(a[i], 1);//值为a[i]的个数+1
52         }
53         memset(b, 0, sizeof(b));
54         for (int i = n; i >= 1; i--)
55         {
56             R[i] = Query(a[i] - 1);
57             Update(a[i], 1);
58         }
59         long long ans = 0;
60         for (int i = 1;i <= n; i++)
61         {
62             ans += L[i] * (n - i - R[i]);
63             ans += R[i] * (i - 1 - L[i]);
64         }
65         printf("%lld\n", ans);
66     }
67     return 0;
68 }
View Code

 

posted @ 2017-08-31 15:22  萌萌的美男子  阅读(154)  评论(0编辑  收藏  举报