---
# System prepended metadata

title: Dãy Liên Tiếp

---

# Dãy Liên Tiếp - Solution


## Subtask 3

Do $1 \le l \le r \le 5000$, và $a_i \le 5000$, ta có thể dùng thuật toán $O(n \times q)$ bằng đếm phân phối như sau:
- Gọi $cnt_i$ là số lần xuất hiện của giá trị $i$ trong dãy $C$ được tạo bởi đoạn $[l,r]$.
- Ta sẽ duyệt qua từng $a_i$ trong $[l,r]$, ta biết rằng giá trị $a_i$ này sẽ xuất hiện trong $(i-l+1)\times(r-i+1)$ đoạn con của đoạn $[l,r]$. Vậy nên, ta cộng thêm cho $cnt_{a_i}$ một lượng bằng $(i-l+1)\times(r-i+1)$.
- Sau đó, ta duyệt các giá trị $i$ trong khoảng từ $[1,5000]$, nếu tổng tiền tố của nó không bé hơn $k$ thì $i$ chính là đáp án của truy vấn.

## Subtask 4

Dựa vào nhận xét, giá trị $a_i$ này sẽ xuất hiện trong $(i-l+1)\times(r-i+1)$ đoạn con của đoạn $[l,r]$, ta có thể biến đổi một chút như sau:
- $(i-l+1)\times(r-i+1) = -i^2 + i\times(r+l) + (r-l+1 - r\times l)$

Từ đây, với mảng $cnt_i$ được định nghĩa như subtask $3$, ta có thể tính $cnt_x = \sum (-i^2 + i\times(r+l) + (r-l+1 - r\times l))$, $\forall i \in [l,r]$ và $a_i = x$.

Do $1 \le a_i \le 100$, ta có thể dùng mảng cộng dồn để tính tương ứng với $3$ giá trị trong phép tính.

## Subtask 5

Xét với mỗi truy vấn, nếu ta hoàn toàn có thể tìm kiếm nhị phân kết quả của nó, tức là chỉ cần kiểm tra xem liệu giá trị $x$ **lớn hơn hoặc bằng** bao nhiêu giá trị của dãy $C$ tạo bởi đoạn $[l,r]$. Tuy nhiên, việc kiểm tra này sẽ mất $O(n)$.

Vậy nên, ta cần áp dụng phương pháp chặt nhị phân song song để xử lí cùng lúc tất cả các truy vấn. Kết hợp thêm với phương pháp sweepline $1$ chiều để check.

Độ phức tạp: $O(n \times log^2)$.
## Subtask 6

Thay vì cần chặt nhị phân song song, ta có thể thay bằng Persistent Tree để cho ra độ phức tạp $O(n\times log)$.

## Code mẫu (subtask $3,4,5$):

```cpp=
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+5;
int n,q;
int a[N];
int mx = 0;
namespace sub3 {
	const int N = 5050;
	int cnt[N];
	void solve () {
		while (q--) {
			int l,r,k; cin >> l >> r >> k;
			int cur = 0;
			for (int i=1; i<=5000; i++) cnt[i] = 0;
			for (int i=l; i<=r; i++) {
				cnt[a[i]] += (i-l+1)*(r-i+1);
			}
			for (int i=1; i<=5000; i++) {
				cur += cnt[i];
				if (cur >= k) {
					cout << i << '\n';
					break;
				}
			}  
		}
	}
}
namespace sub4 {
	int f[101][N],s[101][N],cnt[101][N];
	int get (int i, int l, int r) {
		return (f[i][r]-f[i][l-1])*(r+l) + (s[i][r]-s[i][l-1]) + (cnt[i][r]-cnt[i][l-1])*(r-l+1-r*l);
	}
	void solve () {
		for (int i=1; i<=n; i++) {
			for (int j=1; j<=100; j++) f[j][i] = f[j][i-1],s[j][i] = s[j][i-1],cnt[j][i] = cnt[j][i-1];
			f[a[i]][i] += i;
			s[a[i]][i] += -(i*i);
			cnt[a[i]][i] ++; 
		}
		while (q--) {
			int l,r,k; cin >> l >> r >> k;
			int res = 0;
			for (int i=1; i<=100; i++) {
				res += get(i,l,r);
				if (res >=k) {
					cout << i << '\n';
					break;
				} 
			}
		}
	}
}
namespace sub5 {
	struct fenwick {
		int n;
		vector<int> bit;
		fenwick (int n) : n(n), bit(n+6){}
		void update (int u, int val) {
			while (u <= n) bit[u] += val, u += u&(-u);
		}
		int get (int u) {
			int ans = 0;
			while (u>0) ans += bit[u], u -= u&(-u);
			return ans; 
		}
		void xoa () {
			for (int i=1; i<=n; i++) bit[i] = 0; 
		}
	};
	struct qr {
		int l,r,k;
	}go[N];
	struct vcl {
		int sig,mid,id;
	}; vector<vcl> event[N];
	int l[N],r[N],res[N],val[N];
	void solve () {
		for (int i=1; i<=q; i++) {
			cin >> go[i].l >> go[i].r >> go[i].k;
			l[i] = 1; r[i] = mx;
		}
		bool gone = false;
		fenwick f(mx),s(mx),cnt(mx);
		while (gone == false) {
			gone = true;
			f.xoa(); s.xoa(); cnt.xoa();
			for (int i=1; i<=q; i++) {
				val[i] = 0;
				if (l[i] > r[i]) continue;
				gone = false;
				int mid = (r[i] + l[i]) >> 1;
				event[go[i].l].push_back({1,mid,i});
				event[go[i].r+1].push_back({-1,mid,i});
			}
			for (int i=n; i>=1; i--) {
				f.update (a[i],i);
				s.update (a[i],-(i*i));
				cnt.update (a[i],1);
				for (int cc=0; cc<event[i].size(); cc++) {
					vcl cur = event[i][cc];
					int id = cur.id;
					int add = f.get(cur.mid)*(go[id].l+go[id].r)+s.get(cur.mid)+cnt.get(cur.mid)*(go[id].r-go[id].l+1-go[id].r*go[id].l);
					add = cur.sig*add;
					val[id] += add;
				} 
				event[i].clear();
			}
			event[n+1].clear();
			for (int i=1; i<=q; i++) {
				if (l[i] > r[i]) continue;
				int mid = (r[i] + l[i]) >> 1;
				if (val[i] >= go[i].k) res[i] = mid, r[i] = mid - 1;
				else l[i] = mid + 1;
			}
		}
		for (int i=1; i<=q; i++) cout << res[i] << '\n';
	}
} 
signed main () {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	freopen("DLT.inp","r", stdin);
	freopen("DLT.out", "w", stdout);
	cin >> n >> q;
	for (int i=1; i<=n; i++) cin >> a[i], mx = max (mx,a[i]);
	if (mx <= 5000&&n<=5000&&q<=5000) sub3::solve();
	else if (mx<=100) sub4::solve();
	else sub5::solve();
}
```