#include <iostream> #include <cstdio> #include <string> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <algorithm> #include <cstring> #include <ctime> #include <cassert> #include <unordered_map> using namespace std; #define pb push_back #define mp make_pair #define pii pair<int,int> #define vi vector<int> #define vpii vector<pii> #define SZ(x) ((int)(x.size())) #define fi first #define se second #define FOR(i,n) for(int (i)=0;(i)<(n);++(i)) #define FORI(i,n) for(int (i)=1;(i)<=(n);++(i)) #define IN(x,y) ((y).find((x))!=(y).end()) #define ALL(t) t.begin(),t.end() #define FOREACH(i,t) for (typeof(t.begin()) i=t.begin(); i!=t.end(); i++) #define REP(i,a,b) for(int (i)=(a);(i)<=(b);++i) #define REPD(i,a,b) for(int (i)=(a); (i)>=(b);--i) #define REMAX(a,b) (a)=max((a),(b)); #define REMIN(a,b) (a)=min((a),(b)); #define DBG cerr << "debug here" << endl; #define DBGV(vari) cerr << #vari<< " = "<< (vari) <<endl; const int T = 5; const int N = 1e5; const int Q = 1e5; const int V = 1e9; int a[N]; int runs[N]; unordered_map<int, vi> mem; int solve_strictly_inside_block(int L, int R, int k) { //jesli w ogole nie ma blokow k to 0 auto it = mem.find(k); if (it == mem.end()) return 0; //szukamy czy jakis k jest na indeksie >= L auto it2 = lower_bound(ALL(it->se), L); //jesli nie to 0 if (it2 == it->se.end()) return 0; //jesli pierwszy indeks >= L jest tez > R to 0 if (*it2 > R) return 0; // 2 przypadki do rozwazenia: // 1) *it2 - l + 1 >= k => oznacza, ze ten blok jest poprawny, bo zaczyna sie na indeksie co najmniej L // 2) *it2 - l + 1 < k => oznacza, ze ten blok nie jest poprawny, bo zaczyna sie przed L if (*it2-L+1 < k) { //Przypadek 2) // musimy zinkrementowac it2 zeby wziac pierwszy indeks bloku ktory zaczyna sie na co najmniej L it2++; // jesli nie ma zadnego takiego indeksu to 0 if (it2 == it->se.end()) return 0; // jesli pierwwszy taki indeks jest > R to tez 0 if (*it2 > R) return 0; } // teraz mamy juz przypadek 1) // pierwszy indeks > R na ktorym jest k auto it3 = upper_bound(ALL(it->se), R); return distance(it2, it3); //liczba indeksow w przedziale [it2, it3) } int solve_left_boundary(int L, int R, int k) { // jesli istnieje blok o tych samych wartosciach zaczynajacy sie przed L i konczacy sie w indeksie >= L if (L > 0 && a[L] == a[L-1]) { //sprawdzamy czy dlugosc bloku na indeksie L+k-1 to k+runs[L-1] //taki indeks nie jest w przedziale [L,R] if (L+k-1 > R) return 0; if (runs[L+k-1] == k + runs[L-1]) return 1; return 0; } return 0; } int main() { ios_base::sync_with_stdio(0); int t; cin >> t; assert(t >= 1 && t <= T); while (t--) { int n, q; cin >> n >> q; assert(n >= 1 && n <= N); assert(q >= 1 && q <= Q); int run_len; mem.clear(); FOR(i, n) { cin >> a[i]; assert(a[i] >= 1 && a[i] <= V); if (i == 0 || a[i] != a[i-1]) { run_len = 1; } else { run_len++; } if (mem.find(run_len) == mem.end()) { mem.insert(mp(run_len, vi())); } runs[i] = run_len; mem[run_len].pb(i); } while (q--) { int L, R, k; cin >> L >> R >> k; assert(L >= 1 && L <= n); assert(R >= L && R <= n); assert(k >= 1 && k <= R-L+1); --L, --R; int res = 0; //ile jest blokow dlugosci K w [L,R], ktorych poczatek jest co najmniej w L res += solve_strictly_inside_block(L, R, k); //ile jest blokow dlugosci K w [L,R] zaczynajacych, ktore kontynuluja jakis blok rozpoczynajacy sie przed L res += solve_left_boundary(L, R, k); cout << res << endl; } } return 0; }