SP23776 KQUERYO - K-Query Online

题意

给定序列 aa,多次询问区间里 >k>k 的数的个数,强制在线。

做法

先考虑弱化版,离线算法。离线可以考虑莫队加值域分块,复杂度是 O(mn)O(m \sqrt n)

由于强制在线,这种做法不可行。一种做法是可持久化线段树,另一种是分块。

可以考虑块内二分,每个块 upper_bound>k>k 的位置,零散块直接暴力。

这种做法的复杂度是 O(mnlogn)O(m \sqrt n \log \sqrt n)。可过但是复杂度并不非常优秀,跑了 200200 毫秒,而限时就是 200200 毫秒。

所以最好略微卡常一下。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

const int N = 1e5 + 5;

int n, m, len;

#define Get(x) (int)(x / len + 1)
#define L(x) (int)((x - 1) * len)
int a[N];
vector<int> p[N];
int lans = 0;

int main()
{
	scanf("%d", &n);
	len = max(1, (int)sqrt(n));
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]);
		p[Get(i)].push_back(a[i]);
	}
	for (int i = 1; i <= Get(n); i++) sort(p[i].begin(), p[i].end());
	scanf("%d", &m);
	while (m--)
	{
		int l, r, k;
		scanf("%d%d%d", &l, &r, &k);
		l ^= lans;
		r ^= lans;
		k ^= lans;
		if (l < 1) l = 1;
		if (r > n) r = n;
		lans = 0;
		//printf("%d %d %d\n", l, r, k);
		if (l > r)
		{
			printf("0\n");
			continue;
		}
		if (Get(l) == Get(r))
		{
			for (int i = l; i <= r; i++) lans += a[i] > k;
		}
		else
		{
			int lp = Get(l) + 1, rp = Get(r) - 1;
			int lk = L(lp) - 1, rk = L(Get(r));
			for (int i = lp; i <= rp; i++)
			{
				lans += p[i].end() - 1 - upper_bound(p[i].begin(), p[i].end(), k) + 1;
			}
			for (int i = l; i <= lk; i++) lans += a[i] > k;
			for (int i = rk; i <= r; i++) lans += a[i] > k;
		}
		printf("%d\n", lans);
	}
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示