分块50pts求调
查看原帖
分块50pts求调
464712
ForgetOIDuck楼主2025/7/27 11:54

55 个点 AC,后 55 个点 WA。

采用序列分块套值域分块的做法。

具体来说,维护前 ii 个块第 jj 个值域块的数字数量;前 ii 个块数字 jj 的数字数量。这样一段区间的块数量和就可以用前缀和得到。

每次查询就遍历一遍区间内每个值域块的数量,不断累加,找到答案应在哪一个值域块;再在值域块里面遍历数字找到答案。

对于非整块的数字,我们另维护两个序列,在查询时暴力加,查询完减回去。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, v, m, a[2000002], b[2000002], kcn, kcv, k[2000002], kv[2000002], cnt1[1002][1002], cnt2[1002][200002], nc1[1002], nc2[2000002], t[1002];
ll fd(ll x) {
	ll l = 1, r = v, res = v;
	while (l <= r) {
		ll mid = l + r >> 1;
		if (b[mid] >= x) res = mid, r = mid - 1;
		else l = mid + 1;
	}
	return res;
}
int main() {
	cin >> n >> m;
	kcn = sqrt(n); // 序列块长 
	for (ll i = 1; i <= n; i ++ ) cin >> a[i], b[i] = a[i], k[i] = (i + kcn - 1) / kcn;
	k[n + 1] = n / kcn + 1;
	sort(b + 1, b + n + 1); // 离散化 
	v = unique(b + 1, b + n + 1) - b - 1;
	kcv = sqrt(v);
	for (ll i = 1; i <= v; i ++ ) kv[i] = (i + kcv - 1) / kcv;
	for (ll i = 1; i <= n; i ++ ) {
		a[i] = fd(a[i]);
		cnt1[k[i]][kv[a[i]]] ++; // 值域块数字个数的前缀和,以块为单位 
		cnt2[k[i]][a[i]] ++;// 每个数字个数的前缀和,以块为单位 
	}
	for (ll i = 1; i <= k[n]; i ++ ) {
		for (ll j = 1; j <= kv[v]; j ++ ) cnt1[i][j] += cnt1[i - 1][j];
		for (ll j = 1; j <= v; j ++ ) cnt2[i][j] += cnt2[i - 1][j];
	}
	for (ll l, r, x; m --; ) {
		cin >> l >> r >> x;
		if (k[l] == k[r]) { // 同一块内 
			for (ll i = l; i <= r; i ++ ) nc1[kv[a[i]]] ++, nc2[a[i]] ++;
			ll p = 0, s = 0;
			// 找到值域块 
			while (s < x) p ++, s += nc1[p];
			s -= nc1[p]; p = kcn * p - kcn;
			// 找到答案 
			while (s < x) p ++, s += nc2[p];
			cout << b[p] << "\n";
			for (ll i = l; i <= r; i ++ ) nc1[kv[a[i]]] --, nc2[a[i]] --;
		}
		else {
			for (ll i = l; k[l] == k[l - 1] && k[i] == k[l]; i ++ ) nc1[kv[a[i]]] ++, nc2[a[i]] ++;
			for (ll i = r; k[r] == k[r + 1] && k[i] == k[r]; i -- ) nc1[kv[a[i]]] ++, nc2[a[i]] ++;
			ll p = 0, s = 0, kl = k[l - 1] + 1, kr = k[r + 1] - 1;
			// 找到值域块 
			while (s < x) p ++, s += nc1[p] + (cnt1[kr][p] - cnt1[kl - 1][p]);
			s -= nc1[p] + (cnt1[kr][p] - cnt1[kl - 1][p]);
			p = kcn * p - kcn;
			// 找到答案 
			while (s < x) p ++, s += nc2[p] + (cnt2[kr][p] - cnt2[kl - 1][p]);
			cout << b[p] << "\n";
			for (ll i = l; k[l] == k[l - 1] && k[i] == k[l]; i ++ ) nc1[kv[a[i]]] --, nc2[a[i]] --;
			for (ll i = r; k[r] == k[r + 1] && k[i] == k[r]; i -- ) nc1[kv[a[i]]] --, nc2[a[i]] --;
		}
	}
}
2025/7/27 11:54
加载中...