This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/0560"
#include "./../DataStructure/CulSum2D.cpp"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int h, w, n;
cin >> h >> w >> n;
vector<string> s(h);
for (auto& i : s) cin >> i;
CulSum2D<int> cnt_J(s, [](char c) { return c == 'J'; });
CulSum2D<int> cnt_O(s, [](char c) { return c == 'O'; });
CulSum2D<int> cnt_I(s, [](char c) { return c == 'I'; });
while (n--) {
int y1, x1, y2, x2;
cin >> y1 >> x1 >> y2 >> x2;
y1--;
x1--;
cout << cnt_J(y1, y2, x1, x2) << ' ' << cnt_O(y1, y2, x1, x2) << ' '
<< cnt_I(y1, y2, x1, x2) << '\n';
}
}
#line 1 "test/CulSum2D.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/0560"
#line 2 "DataStructure/CulSum2D.cpp"
#include <vector>
#include <algorithm>
#include <type_traits>
template <class T> class CulSum2D {
public:
using value_type = T;
using data_type = std::vector<std::vector<value_type>>;
using size_type = std::size_t;
private:
size_type h, w;
data_type data;
public:
CulSum2D() = default;
CulSum2D(const data_type& a)
: h(a.size()), w(a.front().size()), data(h + 1, std::vector<value_type>(w + 1)) {
for (size_type i = 0; i < h; ++i) {
for (size_type j = 0; j < w; ++j) {
data[i + 1][j + 1] = data[i][j + 1] + data[i + 1][j] - data[i][j] + a[i][j];
}
}
}
template <class U, class F,
std::enable_if_t<std::is_integral_v<U>, std::nullptr_t> = nullptr>
CulSum2D(const U& _h, const U& _w, F f)
: h(_h), w(_w), data(h + 1, std::vector<value_type>(w + 1)) {
for (size_type i = 0; i < h; ++i) {
for (size_type j = 0; j < w; ++j) {
data[i + 1][j + 1] = data[i][j + 1] + data[i + 1][j] - data[i][j] + f(i, j);
}
}
}
template <class U, class F,
std::enable_if_t<!std::is_integral_v<U>, std::nullptr_t> = nullptr>
CulSum2D(const U& a, F f)
: CulSum2D(a.size(), a.front().size(),
[a, f](size_type i, size_type j) -> value_type { return f(a[i][j]); }) {}
// [y1, y2) * [x1, x2)
value_type operator()(size_type y1, size_type y2, size_type x1, size_type x2) const {
y1 = std::min(y1, h);
y2 = std::min(y2, h);
x1 = std::min(x1, w);
x2 = std::min(x2, w);
return (x1 > x2 || y1 > y2)
? 0
: data[y2][x2] - data[y1][x2] - data[y2][x1] + data[y1][x1];
}
// [0, y) * [0, x)
value_type operator()(size_type y, size_type x) const {
y = std::min(y, h);
x = std::min(x, w);
return data[y][x];
}
const data_type& get_data() const {
return data;
}
};
#line 3 "test/CulSum2D.test.cpp"
#include <iostream>
#line 5 "test/CulSum2D.test.cpp"
#include <string>
using namespace std;
int main() {
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int h, w, n;
cin >> h >> w >> n;
vector<string> s(h);
for (auto& i : s) cin >> i;
CulSum2D<int> cnt_J(s, [](char c) { return c == 'J'; });
CulSum2D<int> cnt_O(s, [](char c) { return c == 'O'; });
CulSum2D<int> cnt_I(s, [](char c) { return c == 'I'; });
while (n--) {
int y1, x1, y2, x2;
cin >> y1 >> x1 >> y2 >> x2;
y1--;
x1--;
cout << cnt_J(y1, y2, x1, x2) << ' ' << cnt_O(y1, y2, x1, x2) << ' '
<< cnt_I(y1, y2, x1, x2) << '\n';
}
}