#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int blo[N], blen;
struct Query {
int l, r, ql, qr, id;
inline bool operator<(const Query& other) const {
if(blo[l] != blo[other.l]) return blo[l] < blo[other.l];
if(blo[l] & 1) return r > other.r;
return r < other.r;
}
} q[N];
struct block_array {
int n, bl;
int a[N], _sum[N];
inline int blo(int x) { return (x + bl - 1) / bl; }
inline void init(int _n, int _bl) {
n = _n;
bl = _bl;
memset(a, 0, sizeof(a));
memset(_sum, 0, sizeof(_sum));
}
inline int operator[](int index) const { return a[index]; }
inline void set(int p, int v) {
_sum[blo(p)] += v - a[p];
a[p] = v;
}
inline void add(int p, int v) {
set(p, a[p] + v);
}
inline int sum(int l, int r) {
int res = 0;
if(blo(l) == blo(r)) {
for(int i = l; i <= r; i++) res += a[i];
return res;
}
int x = blo(l) + 1, y = blo(r) - 1;
while(blo(l) < x) res += a[l++];
while(blo(r) > y) res += a[r--];
for(int i = x; i <= y; i++) res += _sum[i];
return res;
}
};
int n, sn, m;
int a[N], ans1[N], ans2[N];
block_array cnt, vl;
int c_l, c_r;
void update(int pos, int w) {
if(!cnt[a[pos]]) vl.set(a[pos], 1);
cnt.add(a[pos], w);
if(!cnt[a[pos]]) vl.set(a[pos], 0);
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> q[i].l >> q[i].r >> q[i].ql >> q[i].qr;
for(int i = 1; i <= m; i++) q[i].id = i;
blen = max(1, (int)(n / sqrt(m)));
sn = max(1, (int)sqrt(n));
for(int i = 1; i <= n; i++) blo[i] = (i + blen - 1) / blen;
sort(q + 1, q + 1 + m);
cnt.init(n, sn);
vl.init(n, sn);
c_l = 1, c_r = 0;
for(int i = 1; i <= m; i++) {
int l = q[i].l, r = q[i].r, ql = q[i].ql, qr = q[i].qr;
while(c_r < r) update(++c_r, 1);
while(c_l > l) update(--c_l, 1);
while(c_r > r) update(c_r--, -1);
while(c_l < l) update(c_l++, -1);
ans1[q[i].id] = cnt.sum(ql, qr);
ans2[q[i].id] = vl.sum(ql, qr);
}
for(int i = 1; i <= m; i++) {
cout << ans1[i] << ' ' << ans2[i] << '\n';
}
return 0;
}