Сходинкові закономірності#4073

Сходинкові закономірності (Розбір)

Числа, записані на сходинках, є цілими і знаходяться в діапазоні від до 10^6 включно. Побудуємо дерево Фенвіка на масиві довжини 10^6 + 1 (індекси масиву змінюються від до 10^6 включно), яке спочатку заповнено нулями.

Кожного разу, коли детектив проходить сходинку зі значенням , збільшуємо a_{value} на . При цьому в щоденнику він запише суму:

a_0 + a_1 + a_2 + ... + a_{value - 1}

З урахуванням обмежень на вхідні дані, всі обчислення слід виконувати в -бітовому цілочисельному типі.

Приклад

Смоделюємо записи детектива на наведеному прикладі. Індексація масиву починається з . Числа, записані детективом, вказані під стрілками.

Сума чисел, записаних у щоденнику детектива, дорівнює

0 + 1 + 1 + 9 + 4 = 15

Реалізація алгоритму

Нехай максимальний розмір масиву дорівнює . Створимо дерево Фенвіка Fenwick.

#define MAX 1000001
vector<long long> Fenwick;

Функція Summa0_i обчислює значення суми a_0 + a_1 + ... + a_i.

long long Summma0_i(int i)
{
  long long result = 0;
  for (; i >= 0; i = (i & (i + 1)) - 1)
    result += Fenwick[i];
  return result;
}

Функція IncElement збільшує значення елемента: a_i = a_i + delta.

void IncElement(int i, int delta)
{
  for (; i < MAX; i = (i | (i+1)))
    Fenwick[i] += delta;
}

Основна частина програми. Читаємо вхідні дані.

scanf("%d",&tests);
while (tests--)
{
  scanf("%d",&n);

Заповнюємо масив Fenwick нулями.

  Fenwick.assign(MAX,0);

Шукану суму, записану в щоденнику детектива, підраховуватимемо в змінній .

  sum = 0;

Послідовно обробляємо числа, записані на сходинках.

  for (i = 0; i < n; i++)
  {

Для кожного значення , записаного на сходинці, збільшуємо a_{value} на , а також обчислюємо суму всіх раніше зустрінутих чисел, менших за . Ця сума дорівнює a_0 + a_1 + a_2 + ... + a_{value - 1}.

    scanf("%d",&value);
    IncElement(value, value);
    sum += Summma0_i(value - 1);
  }

Виводимо суму всіх чисел, записаних у щоденнику детектива.

  printf("%lld\n",sum);
}