题目链接:https://www.acwing.com/problem/content/243/
解题思路:
由于输入的序列是一个1 - n的一个排列,所以我们可以不用离散化,直接按照顺序依次在树状数组中插入对于的数a[i], 然后每次插入前先询问一次以得到左边比这个数小的数的个数,然后 l_big = i - 1 - l_less, r_less = a[i] - 1 - l_less, r_big = n - a[i] - l_big;然后直接使用2个数进行累加即可。
注意点:
在lowbit, query, insert,的时候仔细一些,别写错了,刚开始我就是写错了一个变量,找了好久才找到了错误的地方(调试了好久)。
贴上代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned long long ULL;
const int maxn = 2e5 + 5;
int n;
int a[maxn], t[maxn];
inline int lowbit(int x) {
int y = -x;
int tmp = x & y;
return tmp;
}
inline ULL query(int x) {
ULL res = 0;
while(x) {
res += t[x];
x -= lowbit(x);
}
return res;
}
inline void insert(int x) {
int tmp = x;
while(x <= n) {
t[x] ++;
x += lowbit(x);
}
}
int main(void) {
// freopen("in.txt", "r", stdin);
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
ULL ans = 0, res = 0;
ULL l_less, r_less, l_big, r_big;
insert(a[1]);
for(int i = 2; i <= n - 1; i ++) {
l_less = query(a[i]);
l_big = i - 1 - l_less;
r_less = a[i] - 1 - l_less;
r_big = n - a[i] - l_big;
ans = ans + l_big * r_big;
res = res + l_less * r_less;
insert(a[i]);
}
printf("%lu %lu", ans, res);
return 0;
}
总结:通过这道题目,我发现树状数组似乎就是一种优化后的前缀和数组,相当于是在前缀和的基础上加上了二进制的思想,使得每次inser 和 query 的时间复杂度都是log n, 而前缀和的insert 的时间复杂度是 0(n), query的时间复杂度是0(1)。感觉就像是进行了一种平衡。