Problem:
惑星探査(Planetary Exploration)
あなたを乗せた超時空移民船は長旅の末，ついに居住可能と思われる惑星を発見した．JOI 星と名付けられたその惑星は，その名の通り「ジャングル(Jungle)」，「海(Ocean)」，「氷(Ice)」の3 種類の地形が入り組んだ過酷な惑星である．簡単な調査により，居住予定地近辺の地図が作成された．居住予定地は南北
M
km, 東西
N
km の長方形の形をしており， 1 km 四方の正方形の区画に分けられている．区画は全部で
MN
個あり，北から
p
行目，西から
q
列目の区画を(
p
,
q
) で表す．北西の角の区画が(1, 1) であり，南東の角の区画が(
M
,
N
) である．各区画の地形は，「ジャングル」，「海」，「氷」のいずれかであり，「ジャングル」はJ, 「海」はO, 「氷」はI の英字1 文字で表される.
さて，詳細な移住計画を立てるにあたり， K 箇所の長方形領域内に「ジャングル」，「海」，「氷」がそれぞれ何区画含まれるかを調べることにした．
課題
居住予定地の情報と，調査対象となる領域の情報が与えられたとき，それぞれの領域について， 「ジャングル」，「海」，「氷」が何区画含まれているかを求めるプログラムを作成せよ．
制限
1 ≤
M
≤ 1000    居住予定地の南北の長さ(km)
1 ≤
N
≤ 1000    居住予定地の東西の長さ(km)
1 ≤
K
≤ 100000    調査対象となる領域の個数
入力
標準入力から以下の入力を読み込め．
1 行目には整数
M
,
N
が空白を区切りとして書かれており，居住予定地が南北に
M
km ，東西に
N
km の広さであることを表す．
2 行目には整数
K
が書かれており，調査対象となる領域の個数を表す．
続く
M
行には居住予定地の情報が書かれている．
i
+ 2 行目(1 ≤
i
≤
M
) には，居住予定地の北から
i
行目に位置する
N
区画の情報を表すJ，O，I からなる
N
文字の文字列が書かれている．
続く
K
行には調査対象となる領域が書かれている．
j
+
M
+ 2 行目(1 ≤
j
≤
K
) には，
j
番目の領域を表す正整数
a
j
,
b
j
,
c
j
,
d
j
が空白を区切りとして書かれている．(
a
j
,
b
j
) は調査領域の北西の角の区画を，(
c
j
,
d
j
) は調査領域の南東の角の区画を表す．ただし，
a
j
,
b
j
,
c
j
,
d
j
は，1 ≤
a
j
≤
c
j
≤
M
, 1 ≤
b
j
≤
d
j
≤
N
を満たす．
出力
標準出力に調査の結果を表す
K
行を出力せよ．出力の
j
行目には， j 番目の調査領域に含まれる「ジャングル」(J) の区画数，「海」(O) の区画数，「氷」(I) の区画数を表す3 つの整数を，この順に空白を区切りとして書け．
採点基準
採点用データのうち，配点の30%分については，
M
≤ 50 かつ
K
≤ 100 を満たす．配点の50%分については，
M
≤ 50 を満たす．
入出力の例
入力例
4 7
4
JIOJOIJ
IOJOIJO
JOIJOOI
OOJJIJO
3 5 4 7
2 2 3 6
2 2 2 2
1 1 4 7
出力例
1 3 2
3 5 2
0 1 0
10 11 7
この入力例では， 2 番目の領域は上図のように「ジャングル」を3 区画，「海」を5 区画，「氷」を2 区画含む．
問題文と自動審判に使われるデータは、
情報オリンピック日本委員会
が作成し公開している問題文と採点用テストデータです。

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include<utility>
#include<set>
#include<deque>
#include <unordered_map>
#include<string>
#include<cmath>

using namespace std;

const int MOD = 100000;
int main() {
	int M, N,K;
	cin >> M >> N>>K;
	
	vector<vector<char>>m(M, vector<char>(N));
	for (int i = 0; i < M; i++) {
		for (int j = 0; j < N; j++) {
			cin >> m[i][j];
		}
	}

	vector<vector<int>>J(M+1, vector<int>(N+1, 0));
	vector<vector<int>>O(M+1, vector<int>(N+1, 0));
	vector<vector<int>>I(M+1, vector<int>(N+1, 0));

	for (int i = 1; i <= M; i++) {
		for (int j = 1; j <= N; j++) {
			if (m[i-1][j-1] == 'J') {
				J[i][j] = 1;
			}
			if (m[i-1][j-1] == 'O') {
				O[i][j] = 1;
			}
			if (m[i-1][j-1] == 'I') {
				I[i][j] = 1;
			}
		}
	}

	for (int i = 1; i < M+1; i++) {
		for (int j = 1; j < N+1; j++) {
			
				J[i][j] +=  J[i - 1][j] + J[i][j - 1] - J[i - 1][j - 1];
			
				O[i][j] += O[i - 1][j] + O[i][j - 1] - O[i - 1][j - 1];
			
				I[i][j] +=  I[i - 1][j] + I[i][j - 1] - I[i - 1][j - 1];
			
		}
	}

	for (int i = 0; i < K; i++) {
		int jc, oc, ic;
		jc = 0;
		oc = 0;
		ic = 0;

		int a, b, c, d;
		cin >> a >> b >> c >> d;

		jc = J[c][d] - J[c][b - 1] - J[a-1][d] + J[a - 1][b - 1];
		oc= O[c][d] - O[c][b - 1] - O[a-1][d] + O[a - 1][b - 1];
		ic=I[c][d] - I[c][b - 1] - I[a-1][d] + I[a - 1][b - 1];
		cout << jc << " " << oc << " " << ic << endl;
	}

}
accuracy: 1
time_ms: 160
memory_kb: 16144
final_rank: 16

code_snippet: #include<iostream>
#include<string>
using namespace std;
int J[1200][1200], O[1200][1200], I[1200][1200];
int H, W, Q; string S;
int main() {
	cin >> H >> W >> Q;
	for (int i = 1; i <= H; i++) {
		cin >> S;
		for (int j = 0; j < S.size(); j++) {
			if (S[j] == 'J')J[i][j + 1]++;
			if (S[j] == 'O')O[i][j + 1]++;
			if (S[j] == 'I')I[i][j + 1]++;
		}
	}
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)J[i][j] += J[i - 1][j]; }
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)J[i][j] += J[i][j - 1]; }
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)O[i][j] += O[i - 1][j]; }
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)O[i][j] += O[i][j - 1]; }
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)I[i][j] += I[i - 1][j]; }
	for (int i = 1; i <= H; i++) { for (int j = 1; j <= W; j++)I[i][j] += I[i][j - 1]; }
	for (int i = 0; i < Q; i++) {
		int ax, ay, bx, by; cin >> ax >> ay >> bx >> by; ax--; ay--;
		int pos1 = J[ax][ay] + J[bx][by] - J[ax][by] - J[bx][ay];
		int pos2 = O[ax][ay] + O[bx][by] - O[ax][by] - O[bx][ay];
		int pos3 = I[ax][ay] + I[bx][by] - I[ax][by] - I[bx][ay];
		cout << pos1 << ' ' << pos2 << ' ' << pos3 << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 19820
final_rank: 15

code_snippet: /**
 * テンプレート出展：http://qiita.com/sorachandu/items/041169d34b9f9b99bcf7
 */
#include <bits/stdc++.h>
using namespace std;
struct Init { Init() { ios::sync_with_stdio(0); cin.tie(0); cout << setprecision(13); } }init;

using ll = long long;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;

#define rep(i, x, limit) for (int i = (int)x; i < (int)limit; i++)
#define REP(i, x, limit) for (int i = (int)x; i <= (int)limit; i++)
#define repl(i, x, limit) for (ll i = (ll)x; i < (ll)limit; i++)
#define REPL(i, x, limit) for (ll i = (ll)x; i <= (ll)limit; i++)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define el '\n'
#define spa " "
#define Yes cout << "Yes" << el
#define No cout << "No" << el
#define YES cout << "YES" << el
#define NO cout << "NO" << el
#define eps (1e-10)
#define Equals(a,b) (fabs((a) - (b)) < eps )
#define debug(x) cerr << #x << " = " << x << el

const double pi = 3.141592653589793238;
const int inf = 1073741823;
const ll infl = 1LL << 60;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

//std::pairをstd::coutに渡すために"<<"処理を書き換えた物
template<typename T1, typename T2>
std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){
    os << "{" << p.first << "," << p.second << "}";
    return os;
}

template<typename T1, typename T2> inline bool chmax(T1 &a, T2 b) {
    bool compare = a < b;
    if(compare) a = b;
    return compare;
}
template<typename T1, typename T2> inline bool chmin(T1 &a, T2 b) {
    bool compare = a > b;
    if(compare) a = b;
    return compare;
}

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

template <class T>
struct CumulativeSum2D {
  vector<vector<T> > data;

  CumulativeSum2D(int W, int H) : data(W + 1, vector<T>(H + 1, 0)) {}

  void add(int x, int y, T z) {
    ++x, ++y;
    if (x >= data.size() || y >= data[0].size()) return;
    data[x][y] += z;
  }

  void build() {
    for (int i = 1; i < data.size(); i++) {
      for (int j = 1; j < data[i].size(); j++) {
        data[i][j] += data[i][j - 1] + data[i - 1][j] - data[i - 1][j - 1];
      }
    }
  }

  T query(int sx, int sy, int gx, int gy) const {
    return (data[gx][gy] - data[sx][gy] - data[gx][sy] + data[sx][sy]);
  }
};

int N, Q, x, y, a, b, c, d,H,W;

int main(void){
  cin >> H >> W >> Q;
  CumulativeSum2D<ll> J(H,W);
  CumulativeSum2D<ll> O(H,W);
  CumulativeSum2D<ll> I(H,W);
  for(int i = 0; i < H; i++){
    string s;
    cin >> s;
    for(int j = 0; j < W; j++){
      if(s[j] == 'J'){
        J.add(i,j,1);
      }else if(s[j] == 'O'){
        O.add(i,j,1);
      }else{
        I.add(i,j,1);
      }
    }
  }
  J.build();
  O.build();
  I.build();
  for(int i = 0; i < Q; i++){
    cin >> a >> b >> c >> d;
    a--;b--;
    cout << J.query(a,b,c,d) << " " << O.query(a,b,c,d) << " " << I.query(a,b,c,d)<< el;
  }
}
accuracy: 1
time_ms: 40
memory_kb: 26728
final_rank: 7

code_snippet: #define INF 4'000'000'000'000'000'037LL
#include <bits/stdc++.h>
using namespace std;
namespace {
using ll = long long;
using ull = unsigned long long;
using pll = pair<ll, ll>;
#define vc vector
template <class T>
using vvc = vc<vc<T>>;
using vl = vc<ll>;
using vpll = vc<pll>;
using vvl = vvc<ll>;
#ifdef __SIZEOF_INT128__
using i128 = __int128_t;
#endif
#define cauto const auto
#define overload4(_1, _2, _3, _4, name, ...) name
#define rep1(i, n) for (ll i = 0, nnnnn = ll(n); i < nnnnn; i++)
#define rep(...) overload4(__VA_ARGS__, rep3, rep2, rep1)(__VA_ARGS__)
#define repi1(i, n) for (int i = 0, nnnnn = int(n); i < nnnnn; i++)
#define repi(...) overload4(__VA_ARGS__, repi3, repi2, repi1)(__VA_ARGS__)
template <class T = ll, class U, class V>
constexpr T ipow(U a, V b)
{
  assert(b >= 0);
  if (b == 0)
    return 1;
  if (a == 0 || a == 1)
    return a;
  if (a < 0 && a == -1)
    return b & 1 ? -1 : 1;
  T res = 1, tmp = a;
  while (true)
  {
    if (b & 1)
      res *= tmp;
    b >>= 1;
    if (b == 0)
      break;
    tmp *= tmp;
  }
  return res;
}
template <class T = ll, class A, class B, class M>
T mul_limited(A a, B b, M m)
{
  assert(a >= 0 && b >= 0 && m >= 0);
  if (b == 0)
    return 0;
  return T(a) > T(m) / T(b) ? T(m) : T(a) * T(b);
}
template <class T = ll, class A, class B>
T mul_limited(A a, B b) { return mul_limited<T>(a, b, INF); }
template <class T = ll, class A, class B, class M>
T pow_limited(A a, B b, M m)
{
  assert(a >= 0 && b >= 0 && m >= 0);
  if (a <= 1 || b == 0)
    return min(ipow<T>(a, b), T(m));
  T res = 1, tmp = a;
  while (true)
  {
    if (b & 1)
    {
      if (res > T(m) / tmp)
        return m;
      res *= tmp;
    }
    b >>= 1;
    if (b == 0)
      break;
    if (tmp > T(m) / tmp)
      return m;
    tmp *= tmp;
  }
  return res;
}
template <class T = ll, class A, class B>
T pow_limited(A a, B b) { return pow_limited<T>(a, b, INF); }
#define ALL(a) (a).begin(), (a).end()
template <class T = ll, class V>
inline T SZ(const V &x) { return x.size(); }
template <class F>
auto gen_vec(const int &n, const F &f)
{
  vc<decltype(f(0))> res(n);
  repi(i, n) res[i] = f(i);
  return res;
}
template <class T, size_t d, size_t i = 0, class V>
auto dvec(const V (&sz)[d], const T &init)
{
  if constexpr (i < d)
    return vc(sz[i], dvec<T, d, i + 1>(sz, init));
  else
    return init;
}
template <class T = ll>
T ctol(const char &c, const string &s)
{
  repi(i, SZ<int>(s)) if (s[i] == c) return i;
  return -1;
}
template <class T = ll>
vc<T> stov(const string &s, const char &first)
{
  return gen_vec(SZ<int>(s), [&](int i) -> T
                 { return s[i] - first; });
}
template <class T = ll>
vc<T> stov(const string &s, const string &t)
{
  return gen_vec(SZ<int>(s), [&](int i) -> T
                 { return ctol(s[i], t); });
}
#if __cplusplus < 202002L
#else
#endif
template <class V>
void unique(V &v) { v.erase(std::unique(ALL(v)), v.end()); }
template <class V, class U>
void rotate(V &v, U k)
{ 
  const U n = v.size();
  k = (k % n + n) % n;
  std::rotate(v.begin(), v.begin() + k, v.end());
}
const vpll DRULgrid = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const vpll DRULplane = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
template <class T>
struct is_random_access_iterator
{
  static constexpr bool value = is_same_v<
    typename iterator_traits<T>::iterator_category,
    random_access_iterator_tag
  >;
};
template <class T>
constexpr bool is_random_access_iterator_v = is_random_access_iterator<T>::value;
#if __cplusplus < 202002L
namespace internal
{
};
#else
#define DEFAULT_COMP ranges::less
#endif
#if __cplusplus < 202002L
#else
inline constexpr ll bit_width(ll x) { return std::bit_width((ull)x); }
inline constexpr ll bit_floor(ll x) { return std::bit_floor((ull)x); }
inline constexpr ll bit_ceil(ll x) { return std::bit_ceil((ull)x); }
inline constexpr ll countr_zero(ll x) { assert(x != 0); return std::countr_zero((ull)x); }
inline constexpr ll popcount(ll x) { return std::popcount((ull)x); }
inline constexpr bool has_single_bit(ll x) { return std::has_single_bit((ull)x); }
#endif
#define dump(...)
namespace fastio {
static constexpr uint32_t SIZ = 1 << 17;
char ibuf[SIZ];
char obuf[SIZ];
char out[100];
uint32_t pil = 0, pir = 0, por = 0;
struct Pre {
  char num[10000][4];
  constexpr Pre() : num() {
    for (int i = 0; i < 10000; i++) {
      int n = i;
      for (int j = 3; j >= 0; j--) {
        num[i][j] = n % 10 | '0';
        n /= 10;
      }
    }
  }
} constexpr pre;
inline void load() {
  memcpy(ibuf, ibuf + pil, pir - pil);
  pir = pir - pil + fread(ibuf + pir - pil, 1, SIZ - pir + pil, stdin);
  pil = 0;
  if (pir < SIZ) ibuf[pir++] = '\n';
}
inline void flush() {
  fwrite(obuf, 1, por, stdout);
  por = 0;
}
void rd1(string &x) {
  x.clear();
  char c;
  do {
    if (pil + 1 > pir) load();
    c = ibuf[pil++];
  } while (isspace(c));
  do {
    x += c;
    if (pil == pir) load();
    c = ibuf[pil++];
  } while (!isspace(c));
}
template <typename T>
void rd1_integer(T &x) {
  if (pil + 100 > pir) load();
  char c;
  do
    c = ibuf[pil++];
  while (c < '-');
  bool minus = 0;
  if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
    if (c == '-') { minus = 1, c = ibuf[pil++]; }
  }
  x = 0;
  while ('0' <= c) { x = x * 10 + (c & 15), c = ibuf[pil++]; }
  if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
    if (minus) x = -x;
  }
}
void rd1(ll &x) { rd1_integer(x); }
template <class T, class U>
void rd1(pair<T, U> &p) {
  return rd1(p.first), rd1(p.second);
}
template <size_t N = 0, typename T>
void rd1_tuple(T &t) {
  if constexpr (N < std::tuple_size<T>::value) {
    auto &x = std::get<N>(t);
    rd1(x);
    rd1_tuple<N + 1>(t);
  }
}
template <class... T>
void rd1(tuple<T...> &tpl) {
  rd1_tuple(tpl);
}
template <size_t N = 0, typename T>
void rd1(array<T, N> &x) {
  for (auto &d: x) rd1(d);
}
template <class T>
void rd1(vc<T> &x) {
  for (auto &d: x) rd1(d);
}
void read() {}
template <class H, class... T>
void read(H &h, T &... t) {
  rd1(h), read(t...);
}
void wt1(const char c) {
  if (por == SIZ) flush();
  obuf[por++] = c;
}
template <typename T>
void wt1_integer(T x) {
  if (por > SIZ - 100) flush();
  if (x < 0) { obuf[por++] = '-', x = -x; }
  int outi;
  for (outi = 96; x >= 10000; outi -= 4) {
    memcpy(out + outi, pre.num[x % 10000], 4);
    x /= 10000;
  }
  if (x >= 1000) {
    memcpy(obuf + por, pre.num[x], 4);
    por += 4;
  } else if (x >= 100) {
    memcpy(obuf + por, pre.num[x] + 1, 3);
    por += 3;
  } else if (x >= 10) {
    int q = (x * 103) >> 10;
    obuf[por] = q | '0';
    obuf[por + 1] = (x - q * 10) | '0';
    por += 2;
  } else
    obuf[por++] = x | '0';
  memcpy(obuf + por, out + outi + 4, 96 - outi);
  por += 96 - outi;
}
template <class T, enable_if_t<is_integral_v<T>, int> = 0>
void wt1(T x) { wt1_integer(x); }
template <class T, class U>
void wt1(const pair<T, U> &val) {
  wt1(val.first);
  wt1(' ');
  wt1(val.second);
}
template <size_t N = 0, typename T>
void wt1_tuple(const T &t) {
  if constexpr (N < std::tuple_size<T>::value) {
    if constexpr (N > 0) { wt1(' '); }
    const auto x = std::get<N>(t);
    wt1(x);
    wt1_tuple<N + 1>(t);
  }
}
template <class... T>
void wt1(const tuple<T...> &tpl) {
  wt1_tuple(tpl);
}
template <class T, size_t S>
void wt1(const array<T, S> &val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt1(' ');
    wt1(val[i]);
  }
}
template <class T>
void wt1(const vector<T> &val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt1(' ');
    wt1(val[i]);
  }
}
void print() { wt1('\n'); }
template <class Head, class... Tail>
void print(Head &&head, Tail &&... tail) {
  wt1(head);
  if (sizeof...(Tail)) wt1(' ');
  print(forward<Tail>(tail)...);
}
} // namespace fastio
struct Dummy {
  Dummy() { atexit(fastio::flush); }
} dummy;
namespace internal
{
template <class... Ts>
void READnodump(Ts &...a) { fastio::read(a...); }
template <class T>
void READVECnodump(int n, vc<T> &v)
{
  v.resize(n);
  READnodump(v);
}
template <class T, class... Ts>
void READVECnodump(int n, vc<T> &v, vc<Ts> &...vs)
{ READVECnodump(n, v), READVECnodump(n, vs...); }
template <class T>
void READVEC2nodump(int n, int m, vvc<T> &v)
{
  v.assign(n, vc<T>(m));
  READnodump(v);
}
template <class T, class... Ts>
void READVEC2nodump(int n, int m, vvc<T> &v, vvc<Ts> &...vs)
{ READVEC2nodump(n, m, v), READVEC2nodump(n, m, vs...); }
template <class T>
void READJAGnodump(int n, vvc<T> &v)
{
  v.resize(n);
  repi(i, n)
  {
    int k;
    READnodump(k);
    READVECnodump(k, v[i]);
  }
}
template <class T, class... Ts>
void READJAGnodump(int n, vvc<T> &v, vvc<Ts> &...vs)
{ READJAGnodump(n, v), READJAGnodump(n, vs...); }
}; // namespace internal
#define READ(...) internal::READnodump(__VA_ARGS__); dump(__VA_ARGS__)
#define IN(T, ...) T __VA_ARGS__; READ(__VA_ARGS__)
#define LL(...) IN(ll, __VA_ARGS__)
#define READVEC(...) internal::READVECnodump(__VA_ARGS__); dump(__VA_ARGS__)
#define VEC(T, n, ...) vc<T> __VA_ARGS__; READVEC(n, __VA_ARGS__)
#define PRINT fastio::print
template <class T, class U, class P>
pair<T, U> operator+=(pair<T, U> &a, const P &b)
{
  a.first += b.first;
  a.second += b.second;
  return a;
}
template <class T, class U, class P>
pair<T, U> operator+(pair<T, U> &a, const P &b) { return a += b; }
template <class T, size_t n, class A>
array<T, n> operator+=(array<T, n> &a, const A &b)
{
  for (size_t i = 0; i < n; i++)
    a[i] += b[i];
  return a;
}
template <class T, size_t n, class A>
array<T, n> operator+(array<T, n> &a, const A &b) { return a += b; }
namespace internal
{
template <size_t... I, class A, class B>
auto tuple_add_impl(A &a, const B &b, const index_sequence<I...>)
{
  ((get<I>(a) += get<I>(b)), ...);
  return a;
}
}; // namespace internal
template <class... Ts, class Tp>
tuple<Ts...> operator+=(tuple<Ts...> &a, const Tp &b)
{ return internal::tuple_add_impl(a, b, make_index_sequence<tuple_size_v<tuple<Ts...>>>{}); }
template <class... Ts, class Tp>
tuple<Ts...> operator+(tuple<Ts...> &a, const Tp &b) { return a += b; }
namespace internal
{
};
mt19937_64 mt;
template <class T>
struct GroupAddSub
{
  using S = T;
  static constexpr S op(S a, S b) { return a + b; }
  static constexpr S e() { return 0; }
  static constexpr S inv(S a) { return -a; }
};
template <class G = GroupAddSub<ll>>
struct CumulativeSum2D
{
  using S = typename G::S;
private:
  vvc<S> s;
public:
  CumulativeSum2D() {}
  CumulativeSum2D(const vvc<S> &a)
  {
    const int n = a.size();
    if (n == 0)
      return;
    const int m = a[0].size();
    s.assign(n + 1, vc<S>(m + 1, G::e()));
    repi(i, n) repi(j, m) s[i + 1][j + 1] = G::op(s[i + 1][j], a[i][j]);
    repi(j, m) repi(i, n) s[i + 1][j + 1] = G::op(s[i + 1][j + 1], s[i][j + 1]);
  }
  S sum(int ri, int rj)
  {
    if (s.empty())
      return G::e();
    const int n = SZ<int>(s) - 1;
    const int m = SZ<int>(s[0]) - 1;
    assert(0 <= ri && ri <= n);
    assert(0 <= rj && rj <= n);
    return s[ri][rj];
  }
  S sum(int li, int ri, int lj, int rj)
  {
    if (s.empty())
      return G::e();
    const int n = SZ<int>(s) - 1;
    const int m = SZ<int>(s[0]) - 1;
    assert(0 <= li && li <= ri && ri <= n);
    assert(0 <= lj && lj <= rj && rj <= m);
    return G::op(G::op(s[ri][rj], s[li][lj]), G::inv(G::op(s[ri][lj], s[li][rj])));
  }
};
void init() {}
void main2()
{
  LL(M, N, K);
  VEC(string, M, S);
  auto A = gen_vec(M, [&](ll i)
                   { return stov(S.at(i), "JOI"); });
  array<vvl, 3> B;
  B.fill(vvl(M, vl(N, 0)));
  rep(i, M) rep(j, N) B.at(A.at(i).at(j)).at(i).at(j) = 1;
  array<CumulativeSum2D<>, 3> cums;
  rep(k, 3) cums.at(k) = CumulativeSum2D(B.at(k));
  rep(_, K)
  {
    LL(li, lj, ri, rj);
    li--, lj--;
    array<ll, 3> ans;
    rep(k, 3) ans.at(k) = cums.at(k).sum(li, ri, lj, rj);
    PRINT(ans);
  }
}
void test() {}
template <auto init, auto main2, auto test>
struct Main
{
  Main()
  {
    cauto CERR = [](string val, string color)
    {
      string s = "\033[" + color + "m" + val + "\033[m";
      /* コードテストで確認する際にコメントアウトを外す
      cerr << val;
      //*/
    };
    CERR("\n[FAST_IO]\n\n", "32");
    cout << fixed << setprecision(20);
    test();
    init();
    CERR("\n[SINGLE_TESTCASE]\n\n", "36");
    main2();
  }
};
Main<init, main2, test> main_dummy;
}
int main() {}
accuracy: 1
time_ms: 40
memory_kb: 59468
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)

int main(){
    int m,n;
    cin >> m >> n;
    int k;
    cin >> k;
    vector<vector<int>> x(m+1,vector<int>(n+1,0)),y(m+1,vector<int>(n+1,0)),z(m+1,vector<int>(n+1,0));
    rep(i,m){
        int s=0,t=0,u=0;
        string str;
        cin >> str;
        rep(j,n){
            if(str[j]=='J') s++;
            else if(str[j]=='O') t++;
            else u++;
            x[i+1][j+1]=s;
            y[i+1][j+1]=t;
            z[i+1][j+1]=u;//1-based
        }
    }
    vector<vector<int>> X(m+1,vector<int>(n+1,0)),Y(m+1,vector<int>(n+1,0)),Z(m+1,vector<int>(n+1,0));
    for(int j=1;j<n+1;j++){
        for(int i=1;i<m+1;i++){
            X[i][j]=x[i][j]+X[i-1][j];
            Y[i][j]=y[i][j]+Y[i-1][j];
            Z[i][j]=z[i][j]+Z[i-1][j];
        }
    }
    rep(i,k){
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        cout << X[c][d]-X[a-1][d]-X[c][b-1]+X[a-1][b-1] << " ";
        cout << Y[c][d]-Y[a-1][d]-Y[c][b-1]+Y[a-1][b-1] << " ";
        cout << Z[c][d]-Z[a-1][d]-Z[c][b-1]+Z[a-1][b-1] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 26792
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    
    int M, N;
    cin >> M >> N;
    int K;
    cin >> K;
    
    // Initialize prefix sums with (M+1) x (N+1) to handle 1-based indexing and 0 row/column
    vector<vector<int>> sumJ(M+1, vector<int>(N+1, 0));
    vector<vector<int>> sumO(M+1, vector<int>(N+1, 0));
    vector<vector<int>> sumI(M+1, vector<int>(N+1, 0));
    
    // Read grid and compute prefix sums
    for(int i=1; i<=M; ++i){
        string row;
        cin >> row;
        for(int j=1; j<=N; ++j){
            char c = row[j-1];
            sumJ[i][j] = sumJ[i-1][j] + sumJ[i][j-1] - sumJ[i-1][j-1] + (c == 'J' ? 1 : 0);
            sumO[i][j] = sumO[i-1][j] + sumO[i][j-1] - sumO[i-1][j-1] + (c == 'O' ? 1 : 0);
            sumI[i][j] = sumI[i-1][j] + sumI[i][j-1] - sumI[i-1][j-1] + (c == 'I' ? 1 : 0);
        }
    }
    
    // Prepare to store output
    // To speed up output, we can use a buffer
    string output;
    output.reserve((K * 20)); // rough estimate
    
    for(int q=0; q<K; ++q){
        int aj, bj, cj, dj;
        cin >> aj >> bj >> cj >> dj;
        // Calculate counts using prefix sums
        int countJ = sumJ[cj][dj] - sumJ[aj-1][dj] - sumJ[cj][bj-1] + sumJ[aj-1][bj-1];
        int countO = sumO[cj][dj] - sumO[aj-1][dj] - sumO[cj][bj-1] + sumO[aj-1][bj-1];
        int countI = sumI[cj][dj] - sumI[aj-1][dj] - sumI[cj][bj-1] + sumI[aj-1][bj-1];
        // Append to output
        output += to_string(countJ) + " " + to_string(countO) + " " + to_string(countI) + "\n";
    }
    
    // Print all at once
    cout << output;
    
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 20020
final_rank: 5

code_snippet: #line 1 "verify/AOJ-0560.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/challenges/sources/JOI/Final/0560"

#line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.8
 * @date 2024-06-16
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
#line 12 "Library/Template.hpp"
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REVERSE(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define POPCOUNT(x) __builtin_popcount(x)
#define SUM(x) reduce((x).begin(), (x).end())
#define CEIL(nume, deno) ((nume) + (deno) - 1) / (deno)
#define IOTA(x) iota((x).begin(), (x).end(), 0)
#define LOWERBOUND_IDX(arr, val) distance((arr).begin(), lower_bound((arr).begin(), (arr).end(), val))
#define UPPERBOUND_IDX(arr, val) distance((arr).begin(), upper_bound((arr).begin(), (arr).end(), val))

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool chmin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool chmax(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline bool ingrid(T y, T x, T ymax, T xmax){return between(0, y, ymax - 1) && between(0, x, xmax - 1);}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}
template<typename T>
inline T except(T src, T cond, T excp){return (src == cond ? excp : src);}
template<typename T>
inline T min(vector<T> &v){return *min_element((v).begin(), (v).end());}
template<typename T>
inline T max(vector<T> &v){return *max_element((v).begin(), (v).end());}
vector<int> make_sequence(int Size){
    vector<int> ret(Size);
    IOTA(ret);
    return ret;
}
template<typename T>
void make_unique(vector<T> &v){
    sort(v.begin(), v.end());
    auto itr = unique(v.begin(), v.end());
    v.erase(itr, v.end());
}

using ll = int64_t;
using ull = uint64_t;
using ld = long double;

const int INF_INT = numeric_limits<int>::max() >> 2;
const ll INF_LL = numeric_limits<ll>::max() >> 2;

using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vs = vector<string>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vector<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(0 <= next_y and next_y < max_y and 0 <= next_x and next_x < max_x){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}

#ifdef LOGK
#define VARIABLE(var) cerr << "# " << #var << " = " << var << endl;
#else
#define VARIABLE(...) 42
#endif

// ==============================================================
// 
// Main Program Start
// 
// ==============================================================
#line 1 "Library/DataStructure/CumulativeSum2D.hpp"
/**
 * @file CumulativeSum2D.hpp
 * @author log K (lX57)
 * @brief Cumulative Sum 2D - 二次元累積和
 * @version 3.0
 * @date 2024-10-21
 */

#line 10 "Library/DataStructure/CumulativeSum2D.hpp"

template<typename T = int32_t>
struct CumulativeSum2D{
    private:
    int height_, width_;
    vector<vector<T>> data_;

    void Validate(const int y, const int x) const {
        assert(0 <= y && y < height_ - 1);
        assert(0 <= x && x < width_ - 1);
    }

    public:
    CumulativeSum2D(const int height, const int width, const T init_value = 0) : height_(height + 1), width_(width + 1){
        data_.resize(height_);
        for(int i = 0; i < height_; ++i){
            data_.at(i).resize(width_);
        }
    }

    void Build(){
        for(int i = 1; i < height_; ++i){
            for(int j = 0; j < width_; ++j){
                data_[i][j] += data_[i - 1][j];
            }
        }
        for(int i = 0; i < height_; ++i){
            for(int j = 1; j < width_; ++j){
                data_[i][j] += data_[i][j - 1];
            }
        }
    }

    /**
     * @brief 座標 `(y, x)` に値 `value` を代入する。
     * @attention 座標指定は 0-indexで行うこと
     * @param value 代入する値
     */
    void Set(const int y, const int x, const T value){
        Validate(y, x);
        data_[y][x] = value;
    }

    /**
     * @brief 座標 `(y, x)` に値 `value` を加算する。
     * @attention 座標指定は 0-indexで行うこと
     * @param value 加算する値
     */
    void Add(const int y, const int x, const T value){
        Add(y, x, y, x, value);
    }

    /**
     * @brief 長方形領域 `[y1, y2] × [x1, x2]` に値 `value` を加算する。
     * @attention 座標指定は 0-index, 閉区間で行うこと
     * @param y1 長方形領域左上の y 座標
     * @param x1 長方形領域左上の x 座標
     * @param y2 長方形領域右下の y 座標
     * @param x2 長方形領域右下の x 座標
     * @param value 加算する値
     */
    void Add(const int y1, const int x1, const int y2, const int x2, const T value){
        Validate(y1, x1);
        Validate(y2, x2);
        data_[y1][x1] += value;
        data_[y2 + 1][x1] -= value;
        data_[y1][x2 + 1] -= value;
        data_[y2 + 1][x2 + 1] += value;
    }

    /**
     * @brief 長方形領域 `[0, y] × [0, x]` の累積和を計算する。
     * @attention 座標指定は 0-index, 閉区間で行うこと
     * @param y 長方形領域右下の y 座標
     * @param x 長方形領域右下の x 座標
     * @return T 
     */
    T Sum(const int y, const int x) const {
        Validate(y, x);
        return data_[y][x];
    }

    /**
     * @brief 長方形領域 `[y1, y2] × [x1, x2]` の累積和を計算する。
     * @attention 座標指定は 0-index, 閉区間で行うこと
     * @param y1 長方形領域左上の y 座標
     * @param x1 長方形領域左上の x 座標
     * @param y2 長方形領域右下の y 座標
     * @param x2 長方形領域右下の x 座標
     * @param value 加算する値
     * @return T 
     */
    T Sum(const int y1, const int x1, const int y2, const int x2) const {
        Validate(y1, x1);
        Validate(y2, x2);
        T ret = Sum(y2, x2);
        if(y1 > 0) ret -= Sum(y1 - 1, x2);
        if(x1 > 0) ret -= Sum(y2, x1 - 1);
        if(y1 > 0 && x1 > 0) ret += Sum(y1 - 1, x1 - 1);
        return ret;
    }

    T Max() const {
        T ret = data_[0][0];
        for(int i = 0; i < height_; ++i){
            for(int j = 0; j < width_; ++j){
                ret = max(ret, data_[i][j]);
            }
        }
        return ret;
    }

    T Min() const {
        T ret = data_[0][0];
        for(int i = 0; i < height_; ++i){
            for(int j = 0; j < width_; ++j){
                ret = min(ret, data_[i][j]);
            }
        }
        return ret;
    }

    vector<T> &operator[](const int k){
        return data_.at(k);
    }
};
#line 5 "verify/AOJ-0560.test.cpp"

int main(){
    int N, M; cin >> N >> M;
    int K; cin >> K;
    CumulativeSum2D<int> Jcum(N, M), Ocum(N, M), Icum(N, M);
    for(int i = 0; i < N; ++i){
        string S; cin >> S;
        for(int j = 0; j < M; ++j){
            switch(S[j]){
                case 'J': Jcum.Set(i, j, 1); break;
                case 'O': Ocum.Set(i, j, 1); break;
                case 'I': Icum.Set(i, j, 1); break;
            }
        }
    }
    Jcum.Build();
    Ocum.Build();
    Icum.Build();
    for(int i = 0; i < K; ++i){
        int a, b, c, d; cin >> a >> b >> c >> d, --a, --b, --c, --d;
        cout << Jcum.Sum(a, b, c, d) << ' ' << Ocum.Sum(a, b, c, d) << ' ' << Icum.Sum(a, b, c, d) << endl;
    }
}
accuracy: 1
time_ms: 140
memory_kb: 14968
final_rank: 12

code_snippet: #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0560" 

#ifndef DATA_STRUCTURE_PREFIX_SUM_2D_HPP
#define DATA_STRUCTURE_PREFIX_SUM_2D_HPP 1

#include <cassert>
#include <vector>

namespace kk2 {

template <class T> struct PrefixSum2D {
    std::vector<std::vector<T>> acc;
    int h, w;

    constexpr PrefixSum2D() = default;

    constexpr PrefixSum2D(const std::vector<std::vector<T>> &a)
        : acc(a.size() + 1, std::vector<T>(a[0].size() + 1)),
          h((int)a.size()),
          w((int)a[0].size()) {
        for (int i = 0; i < h; ++i) {
            for (int j = 0; j < w; ++j) {
                acc[i + 1][j + 1] = acc[i + 1][j] + acc[i][j + 1] - acc[i][j] + a[i][j];
            }
        }
    }

    constexpr T sum(int li, int lj, int ri, int rj) const {
        assert(0 <= li && li <= ri && ri <= h);
        assert(0 <= lj && lj <= rj && rj <= w);
        return acc[ri][rj] - acc[li][rj] - acc[ri][lj] + acc[li][lj];
    }

    constexpr T get(int i, int j) const {
        assert(0 <= i && i < h);
        assert(0 <= j && j < w);
        return acc[i + 1][j + 1] - acc[i][j + 1] - acc[i + 1][j] + acc[i][j];
    }

    constexpr T operator()(int li, int lj, int ri, int rj) const {
        assert(0 <= li && li <= ri && ri <= h);
        assert(0 <= lj && lj <= rj && rj <= w);
        return acc[ri][rj] - acc[li][rj] - acc[ri][lj] + acc[li][lj];
    }

    constexpr T operator()(int i, int j) const {
        assert(0 <= i && i < h);
        assert(0 <= j && j < w);
        return acc[i + 1][j + 1] - acc[i][j + 1] - acc[i + 1][j] + acc[i][j];
    }
};

} // namespace kk2

#endif // DATA_STRUCTURE_PREFIX_SUM_2D_HPP

// #include "../../data_structure/prefix_sum_2d.hpp"

#ifndef TEMPLATE
#define TEMPLATE 1

#pragma GCC optimize("O3,unroll-loops")

// #include <bits/stdc++.h>
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;

using pi = std::pair<int, int>;
using pl = std::pair<i64, i64>;
using pil = std::pair<int, i64>;
using pli = std::pair<i64, int>;

template <class T> using vc = std::vector<T>;
template <class T> using vvc = std::vector<vc<T>>;
template <class T> using vvvc = std::vector<vvc<T>>;
template <class T> using vvvvc = std::vector<vvvc<T>>;

template <class T> using pq = std::priority_queue<T>;
template <class T> using pqi = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template <class T> constexpr T infty = 0;
template <> constexpr int infty<int> = (1 << 30) - 123;
template <> constexpr i64 infty<i64> = (1ll << 62) - (1ll << 31);
template <> constexpr i128 infty<i128> = (i128(1) << 126) - (i128(1) << 63);
template <> constexpr u32 infty<u32> = infty<int>;
template <> constexpr u64 infty<u64> = infty<i64>;
template <> constexpr u128 infty<u128> = infty<i128>;
template <> constexpr double infty<double> = infty<i64>;
template <> constexpr long double infty<long double> = infty<i64>;

constexpr int mod = 998244353;
constexpr int modu = 1e9 + 7;
constexpr long double PI = 3.14159265358979323846;

namespace kk2 {

template <class T, class... Sizes> auto make_vector(int first, Sizes... sizes) {
    if constexpr (sizeof...(sizes) == 0) {
        return std::vector<T>(first);
    } else {
        return std::vector<decltype(make_vector(sizes...))>(first, make_vector(sizes...));
    }
}

template <class T, class U> void fill_all(std::vector<T> &v, const U &x) {
    std::fill(std::begin(v), std::end(v), T(x));
}

template <class T, class U> void fill_all(std::vector<std::vector<T>> &v, const U &x) {
    for (auto &u : v) fill_all(u, x);
}

} // namespace kk2

template <class T, class S> inline bool chmax(T &a, const S &b) {
    return (a < b ? a = b, 1 : 0);
}

template <class T, class S> inline bool chmin(T &a, const S &b) {
    return (a > b ? a = b, 1 : 0);
}

void Yes(bool b = 1) {
    std::cout << (b ? "Yes\n" : "No\n");
}

void No(bool b = 1) {
    std::cout << (b ? "No\n" : "Yes\n");
}

void YES(bool b = 1) {
    std::cout << (b ? "YES\n" : "NO\n");
}

void NO(bool b = 1) {
    std::cout << (b ? "NO\n" : "YES\n");
}

void yes(bool b = 1) {
    std::cout << (b ? "yes\n" : "no\n");
}

void no(bool b = 1) {
    std::cout << (b ? "no\n" : "yes\n");
}

#define rep1(a) for (i64 _ = 0; _ < (i64)(a); ++_)
#define rep2(i, a) for (i64 i = 0; i < (i64)(a); ++i)
#define rep3(i, a, b) for (i64 i = (a); i < (i64)(b); ++i)
#define repi2(i, a) for (i64 i = (a) - 1; i >= 0; --i)
#define repi3(i, a, b) for (i64 i = (a) - 1; i >= (i64)(b); --i)
#define overload3(a, b, c, d, ...) d
#define rep(...) overload3(__VA_ARGS__, rep3, rep2, rep1)(__VA_ARGS__)
#define repi(...) overload3(__VA_ARGS__, repi3, repi2, rep1)(__VA_ARGS__)

#define fi first
#define se second
#define all(p) std::begin(p), std::end(p)

struct IoSetUp {
    IoSetUp() {
        std::cin.tie(nullptr);
        std::ios::sync_with_stdio(false);
    }
} iosetup;

template <class OStream, class T, class U>
OStream &operator<<(OStream &os, const std::pair<T, U> &p) {
    os << p.first << ' ' << p.second;
    return os;
}

template <class IStream, class T, class U> IStream &operator>>(IStream &is, std::pair<T, U> &p) {
    is >> p.first >> p.second;
    return is;
}

template <class OStream, class T> OStream &operator<<(OStream &os, const std::vector<T> &v) {
    for (int i = 0; i < (int)v.size(); i++) { os << v[i] << (i + 1 == (int)v.size() ? "" : " "); }
    return os;
}

template <class IStream, class T> IStream &operator>>(IStream &is, std::vector<T> &v) {
    for (auto &x : v) is >> x;
    return is;
}

#endif // TEMPLATE

// #include "../../template/template.hpp"

using namespace std;

int main() {
    int n, m, k;
    cin >> n >> m >> k;
    vvc<int> J_init, O_init, I_init;
    J_init = O_init = I_init = vvc<int>(n, vc<int>(m));
    rep (i, n) {
        string s;
        cin >> s;
        rep (j, m) {
            if (s[j] == 'J') J_init[i][j] = 1;
            if (s[j] == 'O') O_init[i][j] = 1;
            if (s[j] == 'I') I_init[i][j] = 1;
        }
    }

    kk2::PrefixSum2D<int> J_ps(J_init), O_ps(O_init), I_ps(I_init);
    rep (k) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        --x1, --y1;
        cout << J_ps(x1, y1, x2, y2) << " " << O_ps(x1, y1, x2, y2) << " " << I_ps(x1, y1, x2, y2) << "\n";
    }

    return 0;
}

// converted!!
accuracy: 1
time_ms: 40
memory_kb: 26432
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
//#include<atcoder/all>
//using namespace atcoder;
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define rep1(i,n) for(int i=1;i<=(int)n;i++)
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
using P = pair<int, int>;
using Pl = pair<ll, ll>;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vd = vector<double>;
using vs = vector<string>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vl = vector<long long>;
using vvl = vector<vl>;
using vvvl = vector<vvl>;
#define inf 947483642//int max
#define linf 900000000000000000
const double PI = 3.1415926535897932384626433832795028841971;
template<typename T>inline bool chmax(T& a, T b) { return ((a < b) ? (a = b, true) : (false)); }
template<typename T>inline bool chmin(T& a, T b) { return ((a > b) ? (a = b, true) : (false)); }
long long llceil(long long a, long long b) { if (a % b == 0) { return a / b; }return (a / b) + 1; }
#define yes cout<<"Yes"<<endl;
#define no cout<<"No"<<endl;
#define yesno(ans) cout<<(ans?"Yes":"No")<<endl;
#define sortu(a) sort(a.begin(),a.end());
#define sortd(a) sort(a.begin(),a.end(),greater());

template<typename T>
struct Cumulativesum2D {
    vector<vector<T>>data;

    Cumulativesum2D(int H, int W) :data(H + 1, vector<T>(W + 1, 0)) {}
    void add(int y, int x, T z) {
        ++x, ++y;
        if (y >= data.size() || x >= data[0].size()) return;
        data[y][x] += z;
        
    }
    void show() {
        for (int i = 1; i < data.size(); i++) {
            for (int j = 1; j < data[i].size(); j++) {
                cout << data[i][j] << " ";
            }
            cout << endl;
        }
    }

    void build() {
        for (int i = 1; i < data.size(); i++) {
            for (int j = 1; j < data[i].size(); j++) {
                data[i][j] += data[i][j - 1] + data[i - 1][j] - data[i - 1][j - 1];
            }
        }
    }

    T query(int sy, int sx, int gy, int gx)const {
        return (data[gy][gx] - data[gy][sx] - data[sy][gx] + data[sy][sx]);
    }

};

int main() {
    
    int h, w; cin >> h >> w;
    int k; cin >> k;
    Cumulativesum2D<int> Jan(h,w);
    Cumulativesum2D<int> Oce(h,w);
    Cumulativesum2D<int> Ice(h,w);
    vs s(h);
    rep(i, h)cin >> s[i];
    rep(i, h) {
        rep(j, w) {
            if (s[i][j] == 'J') {
                Jan.add(i, j,1);
            }else if (s[i][j] == 'O') {
                Oce.add(i, j,1);
            }else if (s[i][j] == 'I') {
                Ice.add(i, j,1);
            }
        }
    }


    Jan.build();
    Oce.build();
    Ice.build();
\
    rep(i, k) {
        int sy, sx, gy, gx;

        cin >> sy >> sx >> gy >> gx;
        sy--, sx--;
        printf("%d %d %d\n", Jan.query(sy, sx, gy, gx), Oce.query(sy, sx, gy, gx), Ice.query(sy, sx, gy, gx));
    }
    return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 17076
final_rank: 14

code_snippet: #line 1 "/opt/library/template.hpp"
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using f128 = __float128;

template <class T>
constexpr T infty = 0;
template <>
constexpr int infty<int> = 1'000'001'000;
template <>
constexpr ll infty<ll> = ll(infty<int>) * infty<int> * 2;
template <>
constexpr u32 infty<u32> = infty<int>;
template <>
constexpr u64 infty<u64> = infty<ll>;
template <>
constexpr i128 infty<i128> = i128(infty<ll>) * infty<ll>;
template <>
constexpr double infty<double> = infty<ll>;
template <>
constexpr long double infty<long double> = infty<ll>;
#define inf infty<ll>

using pi = pair<ll, ll>;
using vi = vector<ll>;
using vvi = vector<vector<ll>>;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
template <class T>
using pq = priority_queue<T>;
template <class T>
using pqg = priority_queue<T, vector<T>, greater<T>>;

#define vv(type, name, h, ...) \
  vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...)   \
  vector<vector<vector<type>>> name( \
      h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)       \
  vector<vector<vector<vector<type>>>> name( \
      a, vector<vector<vector<type>>>(       \
             b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))

#define rep1(a) for (ll _ = 0; _ < (ll)(a); ++_)
#define rep2(i, a) for (ll i = 0; i < (ll)(a); ++i)
#define rep3(i, a, b) for (ll i = a; i < (ll)(b); ++i)
#define rep4(i, a, b, c) for (ll i = a; i < (ll)(b); i += (c))
#define rrep1(a) for (ll i = (a)-1; i >= (ll)(0); --i)
#define rrep2(i, a) for (ll i = (a)-1; i >= (ll)(0); --i)
#define rrep3(i, a, b) for (ll i = (b)-1; i >= (ll)(a); --i)
#define rrep4(i, a, b, c) for (ll i = (b)-1; i >= (ll)(a); i -= (c))
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define rrep(...) overload4(__VA_ARGS__, rrep4, rrep3, rrep2, rrep1)(__VA_ARGS__)

#define all(x) (x).begin(),(x).end()
#define len(x) (ll)(x.size())
#define elif else if
#define bit(x, i) (((x)>>(i))&1)

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second

#define stoi stoll
#define abs llabs

#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define LB(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define UB(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) \
  sort(all(x)), x.erase(unique(all(x)), x.end()), x.shrink_to_fit()

ll popcnt(ll x) { return __builtin_popcountll(x); }
ll popcnt(u64 x) { return __builtin_popcountll(x); }
ll popcnt_mod_2(ll x) { return __builtin_parityll(x); }
ll popcnt_mod_2(u64 x) { return __builtin_parityll(x); }
ll topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
ll topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
ll lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
ll lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
T floor(T a, T b) {
  return a / b - (a % b && (a ^ b) < 0);
}
template <typename T>
T ceil(T x, T y) {
  return floor(x + y - 1, y);
}
template <typename T>
T bmod(T x, T y) {
  return x - y * floor(x, y);
}
template <typename T>
pair<T, T> divmod(T x, T y) {
  T q = floor(x, y);
  return {q, x - q * y};
}

template<typename T> T SUM(const vector<T> &A) {
  T s = 0; for (auto &&a: A) s += a;
  return s;
}

template <typename T>
T POP(queue<T> &que) {
  T a = que.front();
  que.pop();
  return a;
}
template <typename T>
T POP(deque<T> &que) {
  T a = que.front();
  que.pop_front();
  return a;
}
template <typename T>
T POP(pq<T> &que) {
  T a = que.top();
  que.pop();
  return a;
}
template <typename T>
T POP(pqg<T> &que) {
  T a = que.top();
  que.pop();
  return a;
}
template <typename T>
T POP(vc<T> &que) {
  T a = que.back();
  que.pop_back();
  return a;
}

template <typename F>
ll binary_search(F check, ll ok, ll ng, bool check_ok = true) {
  if (check_ok) assert(check(ok));
  while (abs(ok - ng) > 1) {
    auto x = (ng + ok) / 2;
    (check(x) ? ok : ng) = x;
  }
  return ok;
}
template <typename F>
double binary_search_real(F check, double ok, double ng, ll iter = 100) {
  rep(iter) {
    double x = (ok + ng) / 2;
    (check(x) ? ok : ng) = x;
  }
  return (ok + ng) / 2;
}

// ? は -1
vc<int> s_to_vi(const string &S, char first_char) {
  vc<int> A(S.size());
  rep(i, S.size()) { A[i] = (S[i] != '?' ? S[i] - first_char : -1); }
  return A;
}

template <typename T, typename U>
vc<T> cumsum(vc<U> &A, ll off = 1) {
  ll N = A.size();
  vc<T> B(N + 1);
  rep(i, N) { B[i + 1] = B[i] + A[i]; }
  if (off == 0) B.erase(B.begin());
  return B;
}

// stable sort
template <typename T>
vi argsort(const vector<T> &A) {
  vi ids(len(A));
  iota(all(ids), 0);
  sort(all(ids),
       [&](ll i, ll j) { return (A[i] == A[j] ? i < j : A[i] < A[j]); });
  return ids;
}

// A[I[0]], A[I[1]], ...
template <typename T>
vc<T> rearrange(const vc<T> &A, const vi &I) {
  vc<T> B(len(I));
  rep(i, len(I)) B[i] = A[I[i]];
  return B;
}

template<typename T> inline bool chmax(T &a, T b) {return ((a<b)?(a=b,true):(false));}
template<typename T> inline bool chmin(T &a, T b) {return ((a>b)?(a=b,true):(false));}

inline void wt(const char c) { cout << c; }
inline void wt(const string s) { cout << s; }
inline void wt(const char *s) { cout << s; }

template <typename T>
void wt_integer(T x) {
  if (x < 0) { cout << (i64)(x); }
  else { cout << (u64)(x); }
}
template <typename T>
void wt_real(T x) {
  cout << fixed << setprecision(15) << (long double)(x);
}

inline void wt(int x) { wt_integer(x); }
inline void wt(ll x) { wt_integer(x); }
inline void wt(i128 x) { wt_integer(x); }
inline void wt(u32 x) { wt_integer(x); }
inline void wt(u64 x) { wt_integer(x); }
inline void wt(u128 x) { wt_integer(x); }
inline void wt(double x) { wt_real(x); }
inline void wt(long double x) { wt_real(x); }
inline void wt(f128 x) { wt_real(x); }

template <class T, class U>
void wt(const pair<T, U> val) {
  wt(val.first); wt(' '); wt(val.second);
}
template <size_t N = 0, typename T>
void wt_tuple(const T t) {
  if constexpr (N < std::tuple_size<T>::value) {
    if constexpr (N > 0) { wt(' '); }
    const auto x = std::get<N>(t);
    wt(x);
    wt_tuple<N + 1>(t);
  }
}
template <class... T>
void wt(tuple<T...> tpl) {
  wt_tuple(tpl);
}
template <class T, size_t S>
void wt(const array<T, S> val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}
template <class T>
void wt(const vector<T> val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}

void print() { wt('\n'); }
template <class Head, class... Tail>
void print(Head &&head, Tail &&... tail) {
  wt(head);
  if (sizeof...(Tail)) wt(' ');
  print(forward<Tail>(tail)...);
}

void YES(bool t = 1) { print(t ? "YES" : "NO"); }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { print(t ? "Yes" : "No"); }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { print(t ? "yes" : "no"); }
void no(bool t = 1) { yes(!t); }
void onez(bool t = 1) { print(t ? 1 : 0); }
#define endl '\n'
#define dump(x) {cerr << #x " = " << x << '\n';}
#line 2 "main.cpp"

int solve();
int main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  while (!solve()) {break;}
  return 0;
}

int solve() {
  ll M, N, K;
  cin >> M >> N >> K;
  vc<string> r(M);
  rep(i, M) cin >> r[i];
  string JOI="JOI";
  vvv(ll, s, len(JOI), M, N, 0);
  rep(k, len(JOI)) {
    rep(i, M) rep(j, N) {
      if (JOI[k] == r[i][j]) s[k][i][j]++;
    }
  }
  rep(k, len(JOI)) {
    rep(i, 1, M) {
      rep(j, N) {
        s[k][i][j] += s[k][i-1][j];
      }
    }
    rep(i, M) {
      rep(j, 1, N) {
        s[k][i][j] += s[k][i][j-1];
      }
    }
  }
  rep(K) {
    ll a, b, c, d;
    cin >> a >> b >> c >> d;
    a--; b--; c--; d--;
    vi ans(3, 0);
    rep(k, len(JOI)) {
      ans[k] = s[k][c][d];
      if (a >= 1) ans[k] -= s[k][a-1][d];
      if (b >= 1) ans[k] -= s[k][c][b-1];
      if ((a >= 1) and (b >= 1)) ans[k] += s[k][a-1][b-1];
    }
    print(ans);
  }
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 35144
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
#define all(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)

int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    
    ll M,N,K;
    cin>>M>>N>>K;
    vvvll D(3,vvll(M+1,vll(N+1,0)));
    rep(i,M){
        string S;
        cin>>S;
        rep(j,N){
            if(S[j]=='J')D[0][i+1][j+1]++;
            else if(S[j]=='O')D[1][i+1][j+1]++;
            else if(S[j]=='I')D[2][i+1][j+1]++;
        }
    }
    rep(k,3){
        rep(m,M)rep(n,N+1)D[k][m+1][n]+=D[k][m][n];
        rep(m,M+1)rep(n,N)D[k][m][n+1]+=D[k][m][n];
    }
    rep(k,K){
        ll A,B,C,DD;
        cin>>A>>B>>C>>DD;
        A--;B--;
        rep(i,3){
            cout<<D[i][C][DD]+D[i][A][B]-D[i][C][B]-D[i][A][DD]<<" \n"[i==2];
        }
    }

}
accuracy: 1
time_ms: 50
memory_kb: 34228
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define all(v) v.begin(), v.end()
#define rep(i, begin, end) for(auto i = (begin); i < (end); i++)
#define rrep(i, end, begin) for(auto i = (end) - 1; i >= (begin); i--)
template<class T> inline bool chmin(T& a, T b){ if (a > b){ a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b){ if (a < b){ a = b; return true; } return false; }
template<class T> inline T roundup(T a, T b){ return (a + b - 1) / b; }
constexpr int dy[] = {0, 1, 0, -1, 1, 1, -1, -1, 0};
constexpr int dx[] = {1, 0, -1, 0, 1, -1, 1, -1, 0};
using ll = long long;
constexpr ll INF = 1e9;
struct Edge{ int to; ll cost; Edge(int to, ll cost) : to(to), cost(cost) {} };
using Graph = vector<vector<int>>;

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    
    int n, m, k;
    cin >> n >> m >> k;
    vector info(n, vector(m, '#'));
    rep(i, 0, n) rep(j, 0, m) cin >> info[i][j];
    
    vector sum_j(vector(n, vector(m, 0)));
    vector sum_o(vector(n, vector(m, 0)));
    vector sum_i(vector(n, vector(m, 0)));
    rep(i, 0, n) rep(j, 0, m){
        sum_j[i][j] = info[i][j] == 'J';
        if(i > 0) sum_j[i][j] += sum_j[i-1][j];
        if(j > 0) sum_j[i][j] += sum_j[i][j-1];
        if(i > 0 && j > 0) sum_j[i][j] -= sum_j[i-1][j-1];
    }
    rep(i, 0, n) rep(j, 0, m){
        sum_o[i][j] = info[i][j] == 'O';
        if(i > 0) sum_o[i][j] += sum_o[i-1][j];
        if(j > 0) sum_o[i][j] += sum_o[i][j-1];
        if(i > 0 && j > 0) sum_o[i][j] -= sum_o[i-1][j-1];
    }
    rep(i, 0, n) rep(j, 0, m){
        sum_i[i][j] = info[i][j] == 'I';
        if(i > 0) sum_i[i][j] += sum_i[i-1][j];
        if(j > 0) sum_i[i][j] += sum_i[i][j-1];
        if(i > 0 && j > 0) sum_i[i][j] -= sum_i[i-1][j-1];
    }
    
    auto sum = [](int a, int b, int c, int d, const vector<vector<int>>& sum){
        return sum[c][d] - (b > 0 ? sum[c][b-1] : 0) - (a > 0 ? sum[a-1][d] : 0) + (a > 0 && b > 0 ? sum[a-1][b-1] : 0);
    };
    
    while(k--){
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        a--, b--, c--, d--;
        
        cout << sum(a, b, c, d, sum_j) << " "
             << sum(a, b, c, d, sum_o) << " "
             << sum(a, b, c, d, sum_i) << endl;
    }
}
accuracy: 1
time_ms: 40
memory_kb: 15656
final_rank: 1

code_snippet: #include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
#include <tuple>
#include <cstdint>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <cctype>
#include <climits>
#include <functional>
#include <cassert>
#include <numeric>
#define rep(i, n) for(int i = 0; i < (n); i++)
#define per(i, n) for(int i = (n) - 1; i >= 0; i--)
using ll = long long;
#define vi vector<int>
#define vvi vector<vi>
#define vl vector<ll>
#define pii pair<int, int>
#define pll pair<ll, ll>
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
constexpr int mod = 1000000007;
using namespace std;
template<class T, class U>
bool chmax(T &a, const U &b){ return a < b ? (a = b, 1) : 0; }
template<class T, class U>
bool chmin(T &a, const U &b){ return a > b ? (a = b, 1) : 0; }
template <class T>
struct CumulativeSum2D {
  CumulativeSum2D(const int h, const int w) : h(h), w(w), a(h+1, vector<T>(w+1)){}
  CumulativeSum2D(const vector<vector<T>> &v) : h(v.size()), w(v[0].size()), a(h+1, vector<T>(w+1)){
    for(int i = 0; i < h; i++)
      for(int j = 0; j < w; j++) a[i + 1][j + 1] = v[i][j];
  }
  void set(const int i, const int j, const T x){
    assert(0 <= i && i < h);
    assert(0 <= j && j < w);
    a[i + 1][j + 1] += x;
  }
  void build(){
    for(int i = 0; i < h; i++)
      for(int j = 0; j < w; j++)
        a[i + 1][j + 1] += a[i + 1][j] + a[i][j + 1] - a[i][j];
  }
  T query(const int ly, const int lx, const int ry, const int rx) const{
    assert(0 <= ly && ly <= ry && ry <= h);
    assert(0 <= lx && lx <= rx && rx <= w);
    return a[ry][rx] - a[ry][lx] - a[ly][rx] + a[ly][lx];
  }
  private:
  int h, w;
  vector<vector<T>> a;
};
const string t = "JOI";
int main(){
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n,m,K;
  cin >> n >> m >> K;
  vector<CumulativeSum2D<int>> cnt(3, CumulativeSum2D<int>(n, m));
  rep(i, n){
    string s; cin >> s;
    rep(j, m){
      rep(k, 3) if(s[j] == t[k]){
        cnt[k].set(i, j, 1);
        break;
      }
    }
  }
  rep(i, 3) cnt[i].build();
  rep(_, K){
    int a,b,c,d;
    cin >> a >> b >> c >> d;
    a--; b--;
    rep(i, 3) cout << cnt[i].query(a, b, c, d) << " \n"[i == 2];
  }
}
accuracy: 1
time_ms: 40
memory_kb: 18660
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

#define rep(i, n) for (int i = 0; i < n; i++)
#define REP(i, a, b) for (int i = a; i < b; i++)


int main(){
    int M,N; cin >> M >> N;
    int K; cin >> K;
    vector<string> planet(M); rep(i,M) cin >> planet[i];

    vector<vector<int> > accumJ(M+1, vector<int>(N+1));
    vector<vector<int> > accumO(M+1, vector<int>(N+1));
    vector<vector<int> > accumI(M+1, vector<int>(N+1));

    rep(i,M)
        rep(j,N){
            accumJ[i+1][j+1] = accumJ[i][j+1] + accumJ[i+1][j] - accumJ[i][j];
            accumO[i+1][j+1] = accumO[i][j+1] + accumO[i+1][j] - accumO[i][j];
            accumI[i+1][j+1] = accumI[i][j+1] + accumI[i+1][j] - accumI[i][j];

            if(planet[i][j] == 'J') accumJ[i+1][j+1]++;
            else if(planet[i][j] == 'O') accumO[i+1][j+1]++;
            else accumI[i+1][j+1]++;
        }

    rep(i,K){
        int a,b,c,d; cin >> a >> b >> c >> d;
        a--; b--;
        cout << accumJ[c][d] - accumJ[a][d] - accumJ[c][b] + accumJ[a][b] << " ";
        cout << accumO[c][d] - accumO[a][d] - accumO[c][b] + accumO[a][b] << " ";
        cout << accumI[c][d] - accumI[a][d] - accumI[c][b] + accumI[a][b] << endl;
    }

}
accuracy: 1
time_ms: 190
memory_kb: 15492
final_rank: 18

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
// #include <atcoder/modint>
// #include <atcoder/fenwicktree>
// #include <atcoder/segtree>
// #include <atcoder/scc>

#define int long long
#define all(x) begin(x), end(x)

using namespace std;
// using namespace atcoder;
// using mint = modint998244353;
// using mint = modint1000000007;
using ld = long double;
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vp = vector<pii>;
using vvp = vector<vp>;
using vs = vector<string>;
using vvc = vector<vector<char>>;

void debug(vector<int> a) {
    for (auto x : a) cout << x << ' ';
    cout << endl;
}

void debug(vector<vector<int>> a) {
    for (auto y : a) debug(y);
}

template <typename T1, typename T2>
inline bool chmax(T1 &a, T2 b) {return a < b and (a = b, true);}

template <typename T1, typename T2>
inline bool chmin(T1 &a, T2 b) {return a > b and (a = b, true);}

const int supl = LONG_LONG_MAX - 100;

void main_() {
    int h, w; cin >> h >> w;
    int q; cin >> q;
    vvi js(h, vi(w)), os(h, vi(w)), is(h, vi(w));
    
    for (int i = 0 ; i < h ; i++) for (int j = 0 ; j < w ; j++) {
        char c; cin >> c;
        if (c == 'J') js[i][j] = 1;
        if (c == 'O') os[i][j] = 1;
        if (c == 'I') is[i][j] = 1;
    }
    
    auto mkacum = [&](vvi& a) -> vvi {
        vvi res(h + 1, vi(w + 1));
        for (int i = 0 ; i < h ; i++) for (int j = 0 ; j < w ; j++) {
            res[i + 1][j + 1] = res[i][j + 1] + res[i + 1][j] - res[i][j] + a[i][j];
        }

        return res;
    };


    auto jacum = mkacum(js), iacum = mkacum(is), oacum = mkacum(os);

    // debug(jacum);

    auto query = [](vvi& s, int a, int b, int c, int d) -> int {
        return s[c][d] - s[a - 1][d] - s[c][b - 1] + s[a - 1][b - 1];
    };

    for (int _ = 0 ; _ < q ; _++) {
        int a, b, c, d; cin >> a >> b >> c >> d;
        cout << query(jacum, a, b, c, d) << ' ' << query(oacum, a, b, c, d) << ' ' << query(iacum, a, b, c, d) << endl;
    };
}

signed main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    main_();

    return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 49788
final_rank: 20

code_snippet: #include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

/* macro */

#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)
#define rrep(i, a, n) for (int i = ((int)(n - 1)); i >= (int)(a); i--)
#define Rep(i, a, n) for (i64 i = (i64)(a); i < (i64)(n); i++)
#define RRep(i, a, n) for (i64 i = ((i64)(n - i64(1))); i >= (i64)(a); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define Bit(n) (1LL << (n))

/* macro end */

/* template */

namespace ebi {

#ifdef LOCAL
#define debug(...)                                                      \
    std::cerr << "LINE: " << __LINE__ << "  [" << #__VA_ARGS__ << "]:", \
        debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif

void debug_out() { std::cerr << std::endl; }

template <typename Head, typename... Tail>
void debug_out(Head h, Tail... t) {
    std::cerr << " " << h;
    if (sizeof...(t) > 0) std::cout << " :";
    debug_out(t...);
}

template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &os, const std::pair<T1, T2> &pa) {
    return os << pa.first << " " << pa.second;
}

template <typename T1, typename T2>
std::istream &operator>>(std::istream &os, std::pair<T1, T2> &pa) {
    return os >> pa.first >> pa.second;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
    for (std::size_t i = 0; i < vec.size(); i++)
        os << vec[i] << (i + 1 == vec.size() ? "" : " ");
    return os;
}

template <typename T>
std::istream &operator>>(std::istream &os, std::vector<T> &vec) {
    for (T &e : vec) std::cin >> e;
    return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::optional<T> &opt) {
    if (opt) {
        os << opt.value();
    } else {
        os << "invalid value";
    }
    return os;
}

using std::size_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;

template <class T, T init>
auto make_vector(int n) {
    return std::vector<T>(n, init);
}

template <class T, T init, typename Head, typename... Tail>
auto make_vector(Head n, Tail... ts) {
    return std::vector(n, make_vector<T, init>(ts...));
}

template <class T>
inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
T pow(T x, i64 n) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}

template <class T>
T mod_pow(T x, i64 n, i64 mod) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

template <class T>
T scan() {
    T val;
    std::cin >> val;
    return val;
}

template <class T>
struct Edge {
    int to;
    T cost;
    Edge(int _to, T _cost = 1) : to(_to), cost(_cost) {}
};

template <class T>
struct Graph : std::vector<std::vector<Edge<T>>> {
    using std::vector<std::vector<Edge<T>>>::vector;
    void add_edge(int u, int v, T w, bool directed = false) {
        (*this)[u].emplace_back(v, w);
        if (directed) return;
        (*this)[v].emplace_back(u, w);
    }
};

struct graph : std::vector<std::vector<int>> {
    using std::vector<std::vector<int>>::vector;
    void add_edge(int u, int v, bool directed = false) {
        (*this)[u].emplace_back(v);
        if (directed) return;
        (*this)[v].emplace_back(u);
    }
};

constexpr i64 LNF = std::numeric_limits<i64>::max() / 4;

constexpr int INF = std::numeric_limits<int>::max() / 2;

const std::vector<int> dy = {1, 0, -1, 0, 1, 1, -1, -1};
const std::vector<int> dx = {0, 1, 0, -1, 1, -1, 1, -1};

}  // namespace ebi

template <class T>
struct CumulativeSum2D {
    std::vector<std::vector<T>> data;

    CumulativeSum2D(int W, int H) : data(W + 1, std::vector<T>(H + 1, 0)) {}

    void add(int x, int y, int z) {
        ++x, ++y;
        if (x >= data.size() || y >= data[0].size()) return;
        data[x][y] += z;
    }

    void build() {
        for (int i = 1; i < (int)data.size(); i++) {
            for (int j = 1; j < data[i].size(); j++) {
                data[i][j] +=
                    data[i][j - 1] + data[i - 1][j] - data[i - 1][j - 1];
            }
        }
    }

    T query(int sx, int sy, int gx, int gy) {
        return (data[gx][gy] - data[sx][gy] - data[gx][sy] + data[sx][sy]);
    }
};

namespace ebi {

void main_() {
    int m, n, k;
    std::cin >> m >> n >> k;
    std::vector<std::string> s(m);
    std::cin >> s;
    CumulativeSum2D<int> sumj(m, n), sumo(m, n), sumi(m, n);
    rep(i,0,m) {
        rep(j,0,n) {
            if(s[i][j] == 'J') {
                sumj.add(i, j, 1);
            }
            else if(s[i][j] == 'O') {
                sumo.add(i, j, 1);
            }
            else {
                sumi.add(i, j, 1);
            }
        }
    }
    sumj.build();
    sumo.build();
    sumi.build();
    while(k--) {
        int a,b,c,d;
        std::cin >> a >> b >> c >> d;
        a--; b--;
        std::cout << sumj.query(a, b, c, d) << " " << sumo.query(a, b, c, d) << " " << sumi.query(a, b, c, d) << '\n';
    }
}

}  // namespace ebi

int main() {
    std::cout << std::fixed << std::setprecision(15);
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int t = 1;
    // std::cin >> t;
    while (t--) {
        ebi::main_();
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 15844
final_rank: 2

code_snippet: // 

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

#define rep(i, n) for (int i=0; i<(int)(n); ++(i))
#define rep3(i, m, n) for (int i=(m); (i)<(int)(n); ++(i))
#define repr(i, n) for (int i=(int)(n)-1; (i)>=0; --(i))
#define rep3r(i, m, n) for (int i=(int)(n)-1; (i)>=(int)(m); --(i))
#define all(x) (x).begin(), (x).end()

const int INF = (int)(1e9);
const string tar = "JOI";

template<typename T>
struct BIT {
	int m, n;
	vector<vector<T>> d;
	BIT(int m=0, int n=0) : m(m), n(n), d(m+1, vector<T>(n+1)) {}
	void add(int i, int j, T x=1) {
		for (i++; i<=m; i+=i&-i) {
			int tj = j;
			for (tj++; tj<=n; tj+=tj&-tj) d[i][tj] += x;
		}
	}
	T sum(int i, int j) {
		T x = 0;
		for (i++; i; i-=i&-i) {
			int tj = j;
			for (tj++; tj; tj-=tj&-tj) x += d[i][tj];
		}
		return x;
	}
	T sum(int u, int l, int d, int r) {
		return sum(d-1, r-1) - sum(u-1, r-1) - sum(d-1, l-1) + sum(u-1, l-1);
	}
};

int main() {
	int m, n, k;
	cin >> m >> n >> k;
	vector<string> s(m);
	rep(i, m) cin >> s[i];
	vector<int> a(k), b(k), c(k), d(k);
	rep(i, k) {
		cin >> a[i] >> b[i] >> c[i] >> d[i];
		a[i]--; b[i]--;
	}
	vector<BIT<int>> scnt(3, BIT<int>(m, n));
	rep(i, m) rep(j, n) rep(i2, 3) if (s[i][j] == tar[i2]) scnt[i2].add(i, j, 1);
	rep(i, k) rep(j, 3) cout << scnt[j].sum(a[i], b[i], c[i], d[i]) << (j<2?' ':'\n');
	return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 21992
final_rank: 13

code_snippet: // 

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

#define rep(i, n) for (int i=0; i<(int)(n); ++(i))
#define rep3(i, m, n) for (int i=(m); (i)<(int)(n); ++(i))
#define repr(i, n) for (int i=(int)(n)-1; (i)>=0; --(i))
#define rep3r(i, m, n) for (int i=(int)(n)-1; (i)>=(int)(m); --(i))
#define all(x) (x).begin(), (x).end()

const int INF = (int)(1e9);
const string tar = "JOI";

int main() {
	int m, n, k;
	cin >> m >> n >> k;
	vector<string> s(m);
	rep(i, m) cin >> s[i];
	vector<int> a(k), b(k), c(k), d(k);
	rep(i, k) {
		cin >> a[i] >> b[i] >> c[i] >> d[i];
		a[i]--; b[i]--;
	}
	vector<vector<vector<int>>> ccnt(3, vector<vector<int>>(m+1, vector<int>(n+1)));
	rep(i, m) rep(j, n) rep(i2, 3) {
		int val = s[i][j] == tar[i2] ? 1 : 0;
		ccnt[i2][i+1][j+1] = ccnt[i2][i][j+1] + ccnt[i2][i+1][j] - ccnt[i2][i][j] + val;
	}
	rep(i, k) rep(j, 3) cout << (ccnt[j][c[i]][d[i]]-ccnt[j][a[i]][d[i]]-ccnt[j][c[i]][b[i]]+ccnt[j][a[i]][b[i]]) << (j<2?' ':'\n');
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 22084
final_rank: 8

code_snippet: // 二次元累積和
#include <bits/stdc++.h>

using namespace std;

using VI = vector<int>;
using VVI = vector<vector<int>>;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int m, n, k;
    cin >> m >> n;
    cin >> k;

    VVI j(m + 1, VI(n + 1, 0));
    VVI o(m + 1, VI(n + 1, 0));
    VVI i(m + 1, VI(n + 1, 0));

    for (int r = 1; r <= m; ++r) {
        string s;
        cin >> s;
        s = '0' + s;
        for (int c = 1; c <= n; ++c) {
            j[r][c] = j[r - 1][c] + j[r][c - 1] - j[r - 1][c - 1];
            o[r][c] = o[r - 1][c] + o[r][c - 1] - o[r - 1][c - 1];
            i[r][c] = i[r - 1][c] + i[r][c - 1] - i[r - 1][c - 1];
            if (s[c] == 'J')
                ++j[r][c];
            else if (s[c] == 'O')
                ++o[r][c];
            else
                ++i[r][c];
        }
    }

    while (k--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        int j_cnt = j[c][d] - j[a - 1][d] - j[c][b - 1] + j[a - 1][b - 1];
        int o_cnt = o[c][d] - o[a - 1][d] - o[c][b - 1] + o[a - 1][b - 1];
        int i_cnt = i[c][d] - i[a - 1][d] - i[c][b - 1] + i[a - 1][b - 1];
        cout << j_cnt << " " << o_cnt << " " << i_cnt << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 15096
final_rank: 9

code_snippet: #include<bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;

template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 >& p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  explicit FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};
 
template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}
template< class T >
struct CumulativeSum2D {
  vector< vector< T > > data;

  CumulativeSum2D(int W, int H) : data(W + 1, vector< T >(H + 1, 0)) {}

  void add(int x, int y, T z) {
    ++x, ++y;
    if(x >= data.size() || y >= data[0].size()) return;
    data[x][y] += z;
  }

  void build() {
    for(int i = 1; i < data.size(); i++) {
      for(int j = 1; j < data[i].size(); j++) {
        data[i][j] += data[i][j - 1] + data[i - 1][j] - data[i - 1][j - 1];
      }
    }
  }

  T query(int sx, int sy, int gx, int gy) const {
    return (data[gx][gy] - data[sx][gy] - data[gx][sy] + data[sx][sy]);
  }
};

int main() {
  int N, M, Q;
  cin >> N >> M >> Q;
  vector< CumulativeSum2D< int > > sum(3, CumulativeSum2D< int >(N, M));
  const string P = "JOI";
  for(int i = 0; i < N; i++) {
    string s;
    cin >> s;
    for(int j = 0; j < M; j++) {
      for(int k = 0; k < 3; k++) {
        sum[k].add(i, j, s[j] == P[k]);
      }
    }
  }
  for(int k = 0; k < 3; k++) {
    sum[k].build();
  }
  while(Q--) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    --a, --b;
    vector< int > v(3);
    for(int k = 0; k < 3; k++) {
      v[k] = sum[k].query(a, b, c, d);
    }
    cout << v << "\n";
  }

}
accuracy: 1
time_ms: 40
memory_kb: 18492
final_rank: 3