題目鏈接: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)。感覺就像是進行了一種平衡。