二次离线莫队
二次离线莫队,顾名思义,就是做了两次莫队。第一次莫队是对题目给的询问进行离线(其实就跟普通的莫队是一样的),第二次莫队是对莫队的询问进行离线,也就是本来普通莫队是
假设我们现在的莫队区间是
莫队区间由
再以
此时要计算的就是
注意到最后统计到的每个询问的结果是下一个询问与当前这个询问的答案的差值,所以最后要做一个前缀和得到答案;系数的作用:比如当
最后讲一下实现:为了方便,我们将上文的三元组全部变成四元组,比如当
code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, m, k, len;
int w[N];
LL ans[N];
struct Query
{
int id, l, r;
LL res;
}q[N];
struct Range
{
int id, l, r, t;
};
vector<Range> range[N];
int f[N], g[N];
inline int get_count(int x)
{
int res = 0;
while (x) res += x & 1, x >>= 1;
return res;
}
inline int get(int x)
{
return x / len;
}
bool cmp(const Query& a, const Query& b)
{
int i = get(a.l), j = get(b.l);
if (i != j) return i < j;
return a.r < b.r;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
vector<int> nums;//预处理所有二进制表示下有k个1的数
for (int i = 0; i < 1 << 14; i ++ )
if (get_count(i) == k)
nums.push_back(i);
for (int i = 1; i <= n; i ++ )//预处理f和g数组
{
for (auto y: nums) ++ g[w[i] ^ y];
f[i] = g[w[i + 1]];
}
for (int i = 0; i < m; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
q[i] = {i, l, r};
}
len = sqrt(n);
sort(q, q + m, cmp);//莫队离线
for (int i = 0, L = 1, R = 0; i < m; i ++ )
{
int l = q[i].l, r = q[i].r;
//R+1的情况
if (R < r) range[L - 1].push_back({i, R + 1, r, -1});
while (R < r) q[i].res += f[R ++ ];
//R-1的情况
if (R > r) range[L - 1].push_back({i, r + 1, R, 1});
while (R > r) q[i].res -= f[ -- R];
//L+1的情况
if (L < l) range[R].push_back({i, L, l - 1, -1});
while (L < l) q[i].res += f[L - 1] + !k, L ++ ;
//L-1的情况
if (L > l) range[R].push_back({i, l, L - 1, 1});
while (L > l) q[i].res -= f[L - 2] + !k, L -- ;
}
memset(g, 0, sizeof g);
for (int i = 1; i <= n; i ++ )
{
for (auto y: nums) ++ g[w[i] ^ y];
for (auto& rg: range[i])
{
int id = rg.id, l = rg.l, r = rg.r, t = rg.t;
for (int x = l; x <= r; x ++ )
q[id].res += g[w[x]] * t;
}
}
//记得做前缀和统计答案
for (int i = 1; i < m; i ++ ) q[i].res += q[i - 1].res;
for (int i = 0; i < m; i ++ ) ans[q[i].id] = q[i].res;
for (int i = 0; i < m; i ++ ) printf("%lld\n", ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构