Сума на відрізку#682

Сума на відрізку (Розбір)

Аналіз алгоритму

Кожен запит S_{l,r} можна виконувати за допомогою циклу за час . Існує m \leq 10^6 запитів, довжина масиву складає n \leq 10^6. При лінійному часі виконання запиту нам потрібно не більше n \times m \leq 10^{12} операцій, що дасть Time Limit.

Розглянемо часткові суми масиву :s_1 = a_1;s_2 = a_1 + a_2;s_3 = a_1 + a_2 + a_3;. . .s_n = a_1 + a_2 + a_3 + . . . + a_n;

Обчислити значення s_1, s_2, …, s_n можна в лінійному масиві за час .

Часткові суми

Далі помітимо, щоS_{l,r} = a_l + a_{l + 1} + … + a_r = (a_1 + … + a_l + a_{l + 1} + … + a_r) – (a_1 + … + a_{l-1}) = s_r – s_{l-1}

Таким чином відповісти на запит S_{l,r} можна за , тобто за константний час.

Приклад

Обчислимо суму a_3 + a_4 + a_5 для наведеного в умові прикладу.

Приклад обчислення

Маємо: a_3 + a_4 + a_5 = s_5 – s_2 = 15 – 3 = 12.

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

Оголосимо два робочих одновимірних масиви.

#define MAX 1000001
int a[MAX], s[MAX];

Читаємо вхідний набір чисел у масив a, обчислюємо часткові суми у масиві s.

scanf("%d",&n); s[0] = 0;
for(i = 1; i <= n; i++)
{
    scanf("%d",&a[i]);
    s[i] = s[i-1] + a[i];
}

Обробляємо запитів.

scanf("%d",&m);
for(i = 0; i < m; i++)
{
    scanf("%d %d",&b,&c);
    printf("%d\n",s[c] - s[b-1]);
}

Реалізація алгоритму – SQRT декомпозиція - TLE

#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

int i, n, m, len, x, y;
vector<int> a, b;

int q(int l, int r)
{
    int i, sum = 0;
    int c_l = l / len, c_r = r / len;
    if (c_l == c_r)
        for (i = l; i <= r; i++)
            sum += a[i];
    else
    {
        for (i = l; i <= (c_l + 1)*len - 1; i++)
            sum += a[i];
        for (i = c_l + 1; i <= c_r - 1; i++)
            sum += b[i];
        for (i = c_r * len; i <= r; i++)
            sum += a[i];
    }
    return sum;
}

int main(void)
{
    scanf("%d", &n);
    a.resize(n);
    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);

    len = sqrt(n) + 1;
    b.resize(len);
    for (i = 0; i < n; i++)
        b[i / len] += a[i];

    scanf("%d", &m);
    for (i = 0; i < m; i++)
    {
        scanf("%d %d", &x, &y);
        printf("%d\n", q(x - 1, y - 1));
    }
    return 0;
}

Реалізація алгоритму – запит за лінійний час - TLE

#include <stdio.h>
#define MAX 1000001

int i, j, n, m, b, c, s;
int a[MAX];

int main(void)
{
    scanf("%d", &n);
    for (i = 1; i <= n; i++)
        scanf("%d", &a[i]);

    scanf("%d", &m);
    for (i = 0; i < m; i++)
    {
        scanf("%d %d", &b, &c);
        s = 0;
        for (j = b; j <= c; j++)
            s = s + a[j];
        printf("%d\n", s);
    }
    return 0;
}