《算法竞赛-训练指南》第三章-3.7_LA 3429(树状数组)

来源:互联网 发布:社交网络用户行为研究 编辑:程序博客网 时间:2024/06/08 10:54

树状数组的题目还是说比较简单的吧,主要就是解决动态更新求和的问题。主要运用到的就是lowbit的翻倍求和思想。编码很少,但是主要是思想。一看出现:动态的修改单个元素并求前缀和的题目那就是用树状数组解决此问题的。

别的不多讲了,这道题目还是比较不错的,将的是给你N个不相同的Ai,问你两个一小一大的Ai夹这一个中等的Ai的情况有多少种。解题想法是这样的,既然要求是不相等的,而且A的范围不大,可以想到用hash标记,然后求的同时动态的更新小于Ai的值,很明显就是树状数组了,由此可解。

贴出代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>using namespace std;const int MAXN = 100022;int A[20022];int C[100011];int D[100011];int t[100011];int N;int lowbit(int x){return x & (-x);}void add(int j, int x){for (int i = j; i < MAXN; i += lowbit(i)){t[i] += x;}}int sum(int j){int sum = 0;for (int i = j; i > 0; i -= lowbit(i)){sum += t[i];}return sum;}int main(){int T;scanf("%d", &T);while (T--){scanf("%d", &N);for (int i = 1; i <= N; i++){scanf("%d", &A[i]);}memset(t, 0, sizeof(t));for (int i = 1; i <= N; i++){add(A[i], 1);C[i] = sum(A[i] - 1);}/*for (int i = 0; i <= N; i++){printf("C[%d] = %d\n", i, C[i]);}*/memset(t, 0, sizeof(t));for (int i = N; i >= 1; i--){add(A[i], 1);D[i] = sum(A[i] - 1);}/*for (int i = 0; i <= N; i++){printf("D[%d] = %d\n", i, D[i]);}*/long long sum = 0;for (int i = 1; i <= N; i++){sum += (long long)C[i] * (N - i - D[i]) + (long long)(D[i]) * (i - 1 - C[i]);//cout << sum << endl;}printf("%lld\n", sum);} //system("pause");return 0;}