Подтвердить что ты не робот

Что означает (число и номер) в программировании бит?

Например:

int get(int i) {
    int res = 0;
    while (i) {
        res = (res + tree[i]) % MOD;
        i -= ( (i) & (-i) );
    }
    return res;
}

Функция обновления дерева:

void update(int i, int val) {
    while (i <= m) {
        tree[i] = (tree[i] + val) % MOD;
        i += ( (i) & (-i) );
    }
}

Не могли бы вы объяснить, что они делают в коде, используя ( (i) & (-i) )?

4b9b3361

Ответ 1

Эти две функции представляют собой модифицированную реализацию структуры данных Binary index tree (Fenwick tree).
Здесь представлены две фотографии, которые дополняют ответ MikeCAT, показывающий, как переменная i обновляется для разных значений.

Функция "получить":
Предположим, что максимальное значение входа в функции составляет 15 для простоты представления.
введите описание изображения здесь
A node с номером t в нем представляет дерево [t] в массиве деревьев.
Если вы вызываете get для i, возвращаемое значение представляет собой сумму tree [i] плюс сумма всего дерева элементы массива, что их индекс в массиве является родителем i на картинке, кроме нуля.
Вот несколько примеров:

get(15) = tree[15] + tree[14] + tree[12] + tree[8]
get(14) = tree[14] + tree[12] + tree[8]
get(13) = tree[13] + tree[12] + tree[8]
get(12) = tree[12] + tree[8]
get(11) = tree[11] + tree[10] + tree[8]
get(10) = tree[10] + tree[8]
get(9) = tree[9] + tree[8]
get(8) = tree[8]
get(7) = tree[7] + tree[6] + tree[4]
get(6) = tree[6] + tree[4]
get(5) = tree[5] + tree[4]
get(4) = tree[4]
get(3) = tree[3] + tree[2]
get(2) = tree[2]


Числа на ярлыках на узлах на приведенном выше рисунке имеют свойство, согласно которому каждый родитель node - это метка node минус наименее значимая единица 1 (очень хорошо объясняется ответ @MikeCAT) Функция обновления:
Для простоты картинки предположим, что максимальная длина массива tree равна 16.
Функция update немного сложнее.
введите описание изображения здесь
Он добавляет val в дерево [i] и все элементы tree, что их индекс является родителем node с меткой i на картинке.

update(16, val) --> tree[16] += val;
update(15, val) --> tree[15] += val, tree[16] += val;
update(14, val) --> tree[14] += val, tree[16] += val;
update(13, val) --> tree[13] += val, tree[14] += val; tree[16] += val;
update(12, val) --> tree[12] += val, tree[16] += val;
update(11, val) --> tree[11] += val, tree[12] += val, tree[16] += val;
update(10, val) --> tree[10] += val, tree[12] += val, tree[16] += val;
update(9, val)  --> tree[9] += val, tree[10] += val, tree[12] += val, tree[16] += val;
update(8, val)  --> tree[8] += val, tree[16] += val;
update(7, val)  --> tree[7] += val, tree[8] += val, tree[16] += val;
update(6, val)  --> tree[6] += val, tree[8] += val, tree[16] += val;
update(5, val)  --> tree[5] += val, tree[6] += val, tree[8] += val, tree[16] += val;
update(4, val)  --> tree[4] += val, tree[8] += val, tree[16] += val;
update(3, val)  --> tree[3] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(2, val)  --> tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(1, val)  --> tree[1] += val, tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;

Ответ 2

Позвольте мне предположить, что отрицательное значение представлено с использованием двух дополнений. В этом случае -i можно рассчитать как (~i)+1 (флип-биты, затем добавить 1).

Например, позвольте мне рассмотреть i = 44. Затем, в двоичном формате,

i           = 0000 0000 0000 0000 0000 0000 0010 1100
~i          = 1111 1111 1111 1111 1111 1111 1101 0011
-i = (~i)+1 = 1111 1111 1111 1111 1111 1111 1101 0100
(i) & (-i)  = 0000 0000 0000 0000 0000 0000 0000 0100

Как вы видите, наименьший бит, который равен 1, можно вычислить с помощью (i) & (-i).

Ответ 3

В случае, если кто-то захочет получить более общее доказательство,

Предположим, что x имеет формат a10 k (здесь означает некоторую битовую строку a, за которой следует 1, за которой следуют k нулей).

-x (по определению) то же самое, что и ~x + 1, поэтому

  • x и -x = (заполните)
  • a10 k и - (a10 k) = (отрицание отрицания)
  • a10 k и ~ (a10 k) + 1 = (применить инверсию)
  • a10 k и ~ a01 k + 1 = (добавить 1)
  • a10 k и ~ a10 k= (И между чем-то и его обратным)
  • 0 ш 10 к

Итак, мы остаемся с одним единственным самым правым 1, который, как мы предполагали, существовал.

В предположении о форме x исключается случай, когда x = 0, и в этом случае результат, очевидно, все равно равен нулю.