Ответ 1
Я уже о том, как считать инверсии с помощью Fenwick tree, который является очень эффективным типом двоичного дерева, которое позволяет вычислять агрегаты префикса в последовательности.
Ниже приведен пример adhoc modifcation для вашего сценария:
long long inversions(const vector<int>& a, const vector<int>& b) {
int n = a.size();
vector<int> values(a);
for (int x: b) values.push_back(x);
sort(begin(values), end(values));
vector<int> counts(2*n + 1);
long long res = 0;
for (int i = n - 1; i >= 0; --i) {
// compute sum of prefix 1..rank(a[i]) - 1
for (int v = lower_bound(begin(values), end(values), a[i]) - begin(values);
v;
v -= v & -v)
res += counts[v];
//add 1 to point rank(b[i])
for (int v = lower_bound(begin(values), end(values), b[i]) - begin(values) + 1;
v <= 2*n;
v += v & -v)
counts[v]++;
}
return res;
}
В основном мы просматриваем массивы справа налево, поддерживая структуру данных, которая представляет значения, которые мы уже видели в суффиксе. Для каждого элемента b [i] мы добавляем к окончательному результату число элементов x в структуре данных с x <= b [i] - 1. Затем мы добавляем [i] к структуре данных.
Массив values
используется для сжатия диапазона значений до 1..2n, потому что деревья Фенвика занимают пространство, линейное по размеру диапазона. Мы могли бы избежать этого шага, выбирая более полнофункциональную структуру данных, такую как сбалансированное дерево поиска bjnary с расширением размера поддерева.
Сложность - O (n log n), а постоянный коэффициент очень низкий.