Спочатку розглянемо одномірний варіант задачі. Нехай на числовій прямій задано відрізків [a_i, b_i], де 0 \le a_i, b_i \le 1000. Необхідно визначити, скількома відрізками покривається кожне ціле число на цій прямій.
Оголосимо цілочисельний масив , ініціалізуємо його нулями. Потім для кожного відрізка [a_i, b_i] виконаємо дві операції:
Далі обчислимо префіксні суми в масиві . Значення дорівнює кількості відрізків, що містять число .
Наприклад, нехай дано наступні відрізки: [3; 7], [6; 9], [1; 4], [3; 8], [2; 5]. Ініціалізуємо масив :
Для кожного відрізка [a_i, b_i] виконаємо дві операції: dp[a_i]++; dp[b_i + 1]--.
Тепер розглянемо двовимірний варіант задачі. На площині задано прямокутників з координатами (x_1, y_1) - (x_2, y_2)~(0 \le x_1, y_1, x_2, y_2 \le 1000). Потрібно визначити, скількома прямокутниками покривається кожна клітинка площини.
Оголосимо цілочисельний двовимірний масив , ініціалізуємо його нулями. Потім для кожного прямокутника (x_1, y_1) - (x_2, y_2) виконаємо чотири операції:
Після цього обчислимо префіксні суми в масиві . Значення dp[i][j] буде дорівнювати числу прямокутників, що містять клітинку .
Розглянемо, наприклад, прямокутник (2, 2) - (4, 5).
Приклад
Розглянемо наведений приклад, що містить три прямокутники.
k = 2 шарами фарби покрито квадратів.
Реалізація алгоритму
Оголосимо двовимірний масив .
#define MAX 1001
int dp[MAX][MAX];Читаємо вхідні дані.
scanf("%d %d", &n, &k);
while (n--)
{Для кожного прямокутника (a, b) - (c, d) виконаємо чотири операції.
scanf("%d %d %d %d", &a, &b, &c, &d);
dp[a][b]++;
dp[a][d]--;
dp[c][b]--;
dp[c][d]++;
}В змінній підраховуємо кількість клітинок стіни, покритих рівно шарами фарби.
res = 0;Обчислюємо префіксні суми в масиві .
for (i = 0; i < MAX; i++)
for (j = 0; j < MAX; j++)
{
if (i) dp[i][j] += dp[i - 1][j];
if (j) dp[i][j] += dp[i][j - 1];
if (i && j) dp[i][j] -= dp[i - 1][j - 1];Якщо клітинка покрита шарами фарби, то збільшуємо на ,
if (dp[i][j] == k) res++;
}Виводимо відповідь.
printf("%d\n", res);