嗯..这种算法是我一节语文课想出来的qwq
就是把普通的SparseTable推广到二维的情形。
在一个矩阵中,预处理出以每一个元素为左上角的大小为$$2^0,2^1,2^2…..$$等的矩阵的最大值或最小值,查询时像普通的ST表那样拼起来就可以了
注意的是,如果要查询的区域无法使用四个大小相同的正方形覆盖,则需要将查询的区域拆成两个区域分别查询,详情见代码。
HAOI2007 修筑绿化带
https://www.luogu.org/problemnew/show/P2219
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: main.cpp
* Author: Ytong
*
* Created on 2017年11月10日, 下午2:54
*/
#p\
r\
a\
g\
m\
a GCC optimize("O2")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define DEBUG
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::max;
using std::min;
using std::sort;
using int_t = int;
const int_t LARGE = 1000;
int_t mins[LARGE + 1][LARGE + 1][11];
int_t matrix[LARGE + 1][LARGE + 1];
int_t n, m, a, b, c, d;
int_t pow2[30];
int_t queryMin(int_t r1, int_t c1, int_t r2, int_t c2) {
// cout << "querying min " << r1 << " " << c1 << " " << r2 << " " << c2 << endl;
int_t rowN = r2 - r1 + 1;
int_t colN = c2 - c1 + 1;
//cout << "row n =" << rowN << endl;
//cout << "col n = " << colN << endl;
int_t rowK = floor(log2(rowN));
int_t colK = floor(log2((colN)));
//cout << " k = " << k << endl;
if (rowK > colK) {
int_t mid = (r1 + r2) / 2;
return min(queryMin(r1, c1, mid, c2), queryMin(mid + 1, c1, r2, c2));
} else if (colK > rowK) {
int_t mid = (c1 + c2) / 2;
return min(queryMin(r1, c1, r2, mid), queryMin(r1, mid + 1, r2, c2));
} else {
return min(
min(mins[r1][c1][rowK], mins[r1][c2 - pow2[rowK] + 1][rowK]),
min(mins[r2 - pow2[rowK] + 1][c1][rowK], mins[r2 - pow2[rowK] + 1][c2 - pow2[rowK] + 1][rowK])
);
}
}
int_t getSum(int_t r1, int_t c1, int_t r2, int_t c2) {
return matrix[r2][c2] + matrix[r1 - 1][c1 - 1] - matrix[r1 - 1][c2] - matrix[r2][c1 - 1];
}
int main() {
pow2[0] = 1;
for (int_t i = 1; i <= 29; i++) pow2[i] = pow2[i - 1]*2;
cin >> n >> m >> a >> b >> c>>d;
for (int_t i = 1; i <= n; i++) {
for (int_t j = 1; j <= m; j++) {
cin >> matrix[i][j];
matrix[i][j] += -matrix[i - 1][j - 1] + matrix[i][j - 1] + matrix[i - 1][j];
}
}
//枚举出所有的小矩阵
for (int_t i = 1; i + c - 1 <= n; i++) {
for (int_t j = 1; j + d - 1 <= m; j++) {
mins[i][j][0] = getSum(i, j, i + c - 1, j + d - 1);
}
}
for (int_t k = 1; pow2[k] <= min(n - 1, m - 1); k++) {
for (int_t row = 1; row + pow2[k] + c - 1 <= n; row++) {
for (int_t col = 1; col + pow2[k] + d - 1 <= m; col++) {
mins[row][col][k] = min(
min(mins[row][col][k - 1], mins[row + pow2[k - 1]][col][k - 1]),
min(mins[row][col + pow2[k - 1]][k - 1], mins[row + pow2[k - 1]][col + pow2[k - 1]][k - 1])
);
}
}
}
int_t result = 0;
for (int_t i = 1; i + a - 1 <= n; i++) {
for (int_t j = 1; j + b - 1 <= m; j++) {
int_t x = queryMin(i + 1, j + 1, i + a - 1 - 1 - (c) + 1, j + b - 1 - 1 - (d) + 1);
result = max(result, getSum(i, j, i + a - 1, j + b - 1) - x);
}
}
cout << result;
return 0;
}
HAOI2007 理想的正方形
https://www.luogu.org/problemnew/show/2216
// luogu-judger-enable-o2
// luogu-judger-enable-o2
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: main.cpp
* Author: Ytong
*
* Created on 2017年11月10日, 下午2:54
*/
#p\
r\
a\
g\
m\
a GCC optimize("O2")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define DEBUG
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::max;
using std::min;
using std::sort;
using int_t = int;
const int_t LARGE = 1000;
int_t mins[LARGE + 1][LARGE + 1][11];
int_t maxs[LARGE + 1][LARGE + 1][11];
int_t a, b, n;
int_t pow2[30];
int_t queryMax(int_t r1, int_t c1, int_t r2, int_t c2) {
int_t rowN = r2 - r1 + 1;
int_t colN = c2 - c1 + 1;
int_t k = floor(log2(min(rowN, colN)));
if (rowN > pow2[k + 1]) {
int_t mid = (r1 + r2) / 2;
return max(queryMax(r1, c1, mid, c2), queryMax(mid + 1, c1, r2, c2));
} else if (colN > pow2[k + 1]) {
int_t mid = (c1 + c2) / 2;
return max(queryMax(r1, c1, r2, mid), queryMax(r1, mid + 1, r2, c2));
} else {
return max(
max(maxs[r1][c1][k], maxs[r1][c2 - pow2[k] + 1][k]),
max(maxs[r2 - pow2[k] + 1][c1][k], maxs[r2 - pow2[k] + 1][c2 - pow2[k] + 1][k])
);
}
}
int_t queryMin(int_t r1, int_t c1, int_t r2, int_t c2) {
// cout << "querying min " << r1 << " " << c1 << " " << r2 << " " << c2 << endl;
int_t rowN = r2 - r1 + 1;
int_t colN = c2 - c1 + 1;
//cout << "row n =" << rowN << endl;
//cout << "col n = " << colN << endl;
int_t k = floor(log2(min(rowN, colN)));
//cout << " k = " << k << endl;
if (rowN > pow2[k + 1]) {
int_t mid = (r1 + r2) / 2;
return min(queryMin(r1, c1, mid, c2), queryMin(mid + 1, c1, r2, c2));
} else if (colN > pow2[k + 1]) {
int_t mid = (c1 + c2) / 2;
return min(queryMin(r1, c1, r2, mid), queryMin(r1, mid + 1, r2, c2));
} else {
return min(
// cout << " " << mins[r1][c1][k] << " " << mins[r1][c2 - pow2[k] + 1][k] << " " << mins[r1 - pow2[k] + 1][c1][k] << " "
min(mins[r1][c1][k], mins[r1][c2 - pow2[k] + 1][k]),
min(mins[r2 - pow2[k] + 1][c1][k], mins[r2 - pow2[k] + 1][c2 - pow2[k] + 1][k])
);
}
}
int main() {
pow2[0] = 1;
for (int_t i = 1; i <= 29; i++) pow2[i] = pow2[i - 1]*2;
cin >> a >> b>>n;
for (int_t i = 1; i <= a; i++) {
for (int_t j = 1; j <= b; j++) {
cin >> mins[i][j][0];
maxs[i][j][0] = mins[i][j][0];
}
}
for (int_t k = 1; pow2[k] <= min(a, b); k++) {
for (int_t row = 1; row + pow2[k] - 1 <= a; row++) {
for (int_t col = 1; col + pow2[k] - 1 <= b; col++) {
mins[row][col][k] = min(
min(mins[row][col][k - 1], mins[row + pow2[k - 1]][col][k - 1]),
min(mins[row][col + pow2[k - 1]][k - 1], mins[row + pow2[k - 1]][col + pow2[k - 1]][k - 1])
);
maxs[row][col][k] = max(
max(maxs[row][col][k - 1], maxs[row + pow2[k - 1]][col][k - 1]),
max(maxs[row][col + pow2[k - 1]][k - 1], maxs[row + pow2[k - 1]][col + pow2[k - 1]][k - 1])
);
}
}
}
int_t result = 0x7fffffff;
for (int_t i = 1; i + n - 1 <= a; i++) {
for (int_t j = 1; j + n - 1 <= b; j++) {
result = min(result, queryMax(i, j, i + n - 1, j + n - 1) - queryMin(i, j, i + n - 1, j + n - 1));
}
}
cout << result << endl;
return 0;
}