SP23776 KQUERYO - K-Query Online
题意
给定序列 ,多次询问区间里 的数的个数,强制在线。
做法
先考虑弱化版,离线算法。离线可以考虑莫队加值域分块,复杂度是 。
由于强制在线,这种做法不可行。一种做法是可持久化线段树,另一种是分块。
可以考虑块内二分,每个块 upper_bound 找 的位置,零散块直接暴力。
这种做法的复杂度是 。可过但是复杂度并不非常优秀,跑了 毫秒,而限时就是 毫秒。
所以最好略微卡常一下。
#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;
}

浙公网安备 33010602011771号