使用到了普通的樹狀數組和拓展的樹狀數組。
普通的只能單點修改和區間查詢,利用兩次區間查詢可以做到單點查詢。如果要區間修改時間複雜度是O(n)。
拓展樹狀數組可以區間修改和區間查詢,利用兩次區間操作即可實現單點操作,但增加了一個額外的數組。
題目思路是用一個普通bit記錄該點是否未排序。一個拓展bit記錄被排序次數。
- 然後模擬插入排序,選取最小點,該點左邊的點被排序次數都+1(已排序的點可能會被再次累加,但不影響,原因見第4步)。
- 該點的被排序次數+n,n顯然等於該點左邊未排序的點的數量。
- 接着更新該點的未排序標誌。
- 接着該點將不會參與後續排序,所以可以直接累加該點;由於後續不會再使用該點的被累加次數,所以再次執行第1步時,錯誤累加該點的被排序次數不會對結果造成影響。
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <utility>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
int isDebug = 0;
pair<int, int> childs[20]; // hight, index
int unhappy[20 + 1]; // 拓展bit 記錄被排序次數
int unhappy2[20 + 1];
int counts[20 + 1]; // 普通bit 記錄該點是否未排序
// 普通bit 單點修改 bit[i] += x
void bitAdd(int* bit, int i, int x)
{
while (i < 21) {
bit[i] += x;
i += i & -i;
}
}
// 拓展bit 區間修改 bit[i, N] += x
void bitAdd(int* bit1, int* bit2, int i, int x)
{
int ii = i;
while (i < 21) {
bit1[i] += x;
bit2[i] += x * (ii - 1);
i += i & -i;
}
}
// 普通bit 區間查詢 前i項和
int bitSum(int* bit, int i)
{
int s = 0;
while (i > 0) {
s += bit[i];
i -= i & -i;
}
return s;
}
// 拓展bit 區間查詢 前i項和
int bitSum(int* bit1, int* bit2, int i)
{
int s = 0;
int ii = i;
while (i > 0) {
s += ii * bit1[i] - bit2[i];
i -= i & -i;
}
return s;
}
// 遍歷單點查詢
void debug()
{
if (!isDebug)
return;
int i, last = 0, now = 0;
for (i = 1; i < 6; i++) {
now = bitSum(unhappy, unhappy2, i);
printf("%d\n", now - last);
last = now;
}
printf("\n");
}
int main(void)
{
freopen("q.txt", "r", stdin);
int n, N, h, index;
int last = 0, now = 0, ans = 0;
scanf("%d", &N);
for (n = 0; n < N; n++) {
scanf("%d", &h);
childs[n].first = h;
childs[n].second = n + 1;
}
sort(childs, childs+n);
for (n = 1; n < 21; n++)
bitAdd(counts, n, 1);
debug();
for (n = 1; n < 21; n++)
bitAdd(unhappy, unhappy2, n, 0);
debug();
for (n = 0; n < N; n++) {
index = childs[n].second;
// 1 o[1, index - 1] += 1
bitAdd(unhappy, unhappy2, 1, 1);
debug();
bitAdd(unhappy, unhappy2, index, -1);
debug();
// 2 o[index] += index - n - 1
int leftCount = bitSum(counts, index-1);
bitAdd(unhappy, unhappy2, index, leftCount);
debug();
bitAdd(unhappy, unhappy2, index + 1, -leftCount);
debug();
// 3 計數數組中刪除該節點
bitAdd(counts, index, -1);
// printf("%d %d\n", index, bitSum(unhappy, unhappy2, index) - bitSum(unhappy, unhappy2, index - 1));
// 4
index = bitSum(unhappy, unhappy2, index) - bitSum(unhappy, unhappy2, index - 1);
ans += (1 + index) * index / 2;
}
printf("%d\n", ans);
return 0;
}