FairyWinx's blog

By FairyWinx, 4 years ago, In Russian

Решим следующую задачу: Требуется уметь находить произведение чисел на отрезке по модулю, а также умножать все числа на отрезке на некое число x на отрезке. И все по модулю

Понятно, что это решается обычным деревом отрезков с отложенными массовыми операциями. Но в этом случае мы при каждом вызове функции get и update будем пушить значения в детей, что очень долго (У нас в этом случае будет 4 умножения по модулю в функции push). Давайте научимся делать массовые операции не проталкивая значения в детей.

Утверждение, такой код работает (там есть беды с переполнением, но это остается, как упражнение читателю):

Функция update:

void update(int v, int l, int r, int L, int R, int val) {
    if (R <= l || r <= L)
        return;
    if (L <= l && r <= R) {
        t[v] = (t[v] * pow(val, (r - l))) % MOD;
        mod[v] = (mod[v] * val) % MOD;
        return;
    }

    int m = (l + r) / 2;
    update(v * 2 + 1, l, m, L, R, val);
    update(v * 2, m, r, L, R, val);
    t[v] = t[v * 2 + 1] * t[v * 2] * pow(mod[v], (r - l)) % MOD;
}

Функция get:

int get(int v, int l, int r, int L, int R) {
    if (R <= l || r <= L)
        return 1;
    if (L <= l && r <= R)
        return t[v];

    int m = (l + r) / 2;
    return get(v * 2 + 1, l, m, L, R) * get(v * 2, m, r, L, R) * pow(mod[v], max(L, l) - min(R, r)) % MOD;
}

Почему это так: понятно, что в вершине корректное значение, если мы не смотрим на обновления, которые были сверху. (По аналогии с обычным деревом отрезков). Ну а верхние обновления мы учтем, когда будем спускаться в функции get.

Брать модуль у числа не самое быстрое занятие, поэтому функция push в ДО работает очень долго, и такой способ написания ДО очень сильно ускоряет код (когда я пихал корнячку с таким ДО (ну и там не только операции с ДО были) время с 8 секунд уменьшилось до 6, что очень и очень существенно) Ну и это также работает с минимумом/максимумом/суммой и многими другими функциями, и работает быстрее. Такие вот пироги

  • Vote: I like it
  • +41
  • Vote: I do not like it