Count Good Triplets in an Array

hard fenwick tree counting permutation

Problem

You are given two 0-indexed arrays nums1 and nums2, each a permutation of [0, 1, ..., n − 1]. A good triplet is a set of 3 distinct values that appear in increasing order by position in both arrays. Let pos1[v] and pos2[v] be the index of value v in each array; count triplets (x, y, z) with pos1[x] < pos1[y] < pos1[z] and pos2[x] < pos2[y] < pos2[z]. Return the total number of good triplets.

Inputnums1 = [4,0,1,3,2], nums2 = [4,1,0,2,3]
Output4
The 4 good triplets are (4,0,3), (4,0,2), (4,1,3), and (4,1,2).
Inputnums1 = [2,0,1,3], nums2 = [0,1,2,3]
Output1
Only the triplet (0,1,3) is increasing by position in both arrays.

def good_triplets(nums1, nums2):
    n = len(nums1)
    pos1 = [0] * n
    for i, v in enumerate(nums1):
        pos1[v] = i
    mapped = [pos1[v] for v in nums2]
    bit = [0] * (n + 1)
    def update(i):
        i += 1
        while i <= n:
            bit[i] += 1
            i += i & (-i)
    def query(i):
        s, i = 0, i + 1
        while i > 0:
            s += bit[i]
            i -= i & (-i)
        return s
    ans = 0
    for j, m in enumerate(mapped):
        left = query(m)
        right = (n - 1 - j) - (m - left)
        ans += left * right
        update(m)
    return ans
function goodTriplets(nums1, nums2) {
  const n = nums1.length;
  const pos1 = new Array(n);
  for (let i = 0; i < n; i++) pos1[nums1[i]] = i;
  const mapped = nums2.map(v => pos1[v]);
  const bit = new Array(n + 1).fill(0);
  const update = (i) => {
    for (i++; i <= n; i += i & (-i)) bit[i]++;
  };
  const query = (i) => {
    let s = 0;
    for (i++; i > 0; i -= i & (-i)) s += bit[i];
    return s;
  };
  let ans = 0;
  for (let j = 0; j < n; j++) {
    const m = mapped[j];
    const left = query(m);
    const right = (n - 1 - j) - (m - left);
    ans += left * right;
    update(m);
  }
  return ans;
}
long goodTriplets(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int[] pos1 = new int[n];
    for (int i = 0; i < n; i++) pos1[nums1[i]] = i;
    int[] bit = new int[n + 1];
    long ans = 0;
    for (int j = 0; j < n; j++) {
        int m = pos1[nums2[j]];
        int left = query(bit, m);
        long right = (n - 1 - j) - (long)(m - left);
        ans += (long) left * right;
        update(bit, m, n);
    }
    return ans;
}
void update(int[] bit, int i, int n) {
    for (i++; i <= n; i += i & (-i)) bit[i]++;
}
int query(int[] bit, int i) {
    int s = 0;
    for (i++; i > 0; i -= i & (-i)) s += bit[i];
    return s;
}
long long goodTriplets(vector<int>& nums1, vector<int>& nums2) {
    int n = nums1.size();
    vector<int> pos1(n), bit(n + 1, 0);
    for (int i = 0; i < n; i++) pos1[nums1[i]] = i;
    auto update = [&](int i) {
        for (i++; i <= n; i += i & (-i)) bit[i]++;
    };
    auto query = [&](int i) {
        int s = 0;
        for (i++; i > 0; i -= i & (-i)) s += bit[i];
        return s;
    };
    long long ans = 0;
    for (int j = 0; j < n; j++) {
        int m = pos1[nums2[j]];
        int left = query(m);
        long long right = (n - 1 - j) - (long long)(m - left);
        ans += (long long) left * right;
        update(m);
    }
    return ans;
}
Time: O(n log n) Space: O(n)