题面传送门

莫队二次离线 mol ban tea,大概是这道题让我第一次听说有这东西?

首先看到这类数数对的问题可以考虑莫队,记 \(S\) 为二进制下有 \(k\) 个 \(1\) 的数集,我们实时维护一个桶 \(cnt_i\) 表示当前区间中值为 \(i\) 的数有多少个,那么加入一个数 \(v\) 的时候,答案会增加 \(\sum\limits_{y\in S}cnt_{y\oplus v}\),这样暴力莫队复杂度是 \(n\sqrt{n}\dbinom{14}{k}\),如果你过了我请你吃糖

考虑优化,我们记 \(f(x,l,r)\) 表示当前区间为 \([l,r]\),加入 \(a_x\) 后答案的增量,记 \(\sum\limits_{y\in S}cnt_{y\oplus a_x}\)。考虑莫队中每个端点的移动对答案的贡献,我们以右端点为例,设右端点由 \(r\) 移动到了 \(r'\),这里我们不妨设 \(r'>r\),\(r'<r\) 的情况也同理,那么答案显然会增加 \(\sum\limits_{i=r+1}^{r'}f(i,l,i-1)\),这东西不太好直接求,考虑用差分的思想,将这东西拆成 \(f(i,1,i-1)-f(i,1,l-1)\),那么 \(\Delta=\sum\limits_{i=r+1}^{r'}f(i,1,i-1)-\sum\limits_{i=r+1}^{r'}f(i,1,l-1)\),不难发现第一个 \(\sum\) 里的东西只与 \(i\) 有关,我们可以预处理 \(f(i,1,i-1)\) 的前缀和即可 \(\mathcal O(1)\) 求出,至于怎么求 \(f(i,1,i-1)\)……这个看不出来就有点【数据删除】了罢,就从左往右扫一遍并实时维护一个桶 \(cnt\),扫到 \(a_i\) 的时候 \(f(i,1,i-1)\) 的值就是当时 \(\sum\limits_{x\in S}cnt_{x\oplus a_i}\)。后面那坨东西在线求出不太容易,不过既然叫“莫队二次离线”那就离线一下呗,不难发现所有这样的东西都可以用一个三元组 \((x,l,r)\) 表示 \(\sum\limits_{i=l}^rf(i,1,x)\),我们将这样的询问都挂在 \(x\) 上然后从左往右扫描一遍,还是实时维护一个桶 \(cnt\),不过这时候 \(cnt_v\) 的含义为 \([1,i]\) 中有多少个数 \(j\) 满足 \(v\oplus a_j\in S\),这显然可以在 \(\mathcal O(n\dbinom{14}{k})\) 的时间内求出,然后每遇到一个询问 \((i,l,r)\),就暴力枚举 \(t\in[l,r]\) 并令贡献加上/减去 \(cnt_{a_t}\),由于莫队指针移动的总距离为 \(n\sqrt{n}\) 级别的,因此这里的 \(\sum r-l+1\) 也是 \(n\sqrt{n}\) 级别的,可以通过。

上文所叙述的都是右端点移动的情况,左端点移动的情况大体上也差不多,还是设左端点由 \(l\) 移动到了 \(l'\),\(l'<l\)那么答案的增量就是 \(\sum\limits_{i=l'}^{l-1}f(i,i+1,r)\),这里有一个小小的区别就是不能差分前缀和,而要差分后缀和,即 \(f(i,i+1,r)=f(i,i+1,n)-f(i,r+1,n)\),这两项都可以用类似的方式维护。

最后,由于我们求出的是每次莫队后答案的增量,还需对每次询问的结果求一遍前缀和即可得到每次询问真正的答案。

时间复杂度 \(n\sqrt{n}+n\dbinom{14}{k}\)

最后总结一下莫队二次离线的适用范围:

  • 可以莫队
  • 更新答案的时间不是 \(\mathcal O(1)\)(一个数对答案的贡献与区间中别的数有关,例如比一个数小的数有多少,即 P5501)
const int MAXN=1e5;
const int MAXV=1<<14;
int n,qu,k,a[MAXN+5],blk_sz,blk_cnt;
int bel[MAXN+5],L[MAXN+5],R[MAXN+5];
ll pre[MAXN+5],suf[MAXN+5],anss[MAXN+5];
int buc[MAXV+5];
struct query{
int l,r,id;ll ans;
bool operator <(const query &rhs) const{
if(bel[l]^bel[rhs.l]) return bel[l]<bel[rhs.l];
else if(bel[l]&1) return r<rhs.r;
else return r>rhs.r;
}
} q[MAXN+5];
struct qwq{int l,r,id,op;};
vector<qwq> vl[MAXN+5],vr[MAXN+5];
int main(){
scanf("%d%d%d",&n,&qu,&k);vector<int> v;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<MAXV;i++) if(__builtin_popcount(i)==k) v.pb(i);
blk_sz=(int)pow(n,0.5);blk_cnt=(n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=1;i<=qu;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+qu+1);int cl=1,cr=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];
for(int j:v) pre[i]+=buc[j^a[i]];
buc[a[i]]++;
} memset(buc,0,sizeof(buc));
for(int i=n;i;i--){
suf[i]=suf[i+1];
for(int j:v) suf[i]+=buc[j^a[i]];
buc[a[i]]++;
}
for(int i=1;i<=qu;i++){
q[i].ans=pre[q[i].r]-pre[cr]+suf[q[i].l]-suf[cl];
if(cl<q[i].l) vr[cr+1].pb({cl,q[i].l-1,i,1});
if(cl>q[i].l) vr[cr+1].pb({q[i].l,cl-1,i,-1});
if(cr<q[i].r) vl[q[i].l-1].pb({cr+1,q[i].r,i,-1});
if(cr>q[i].r) vl[q[i].l-1].pb({q[i].r+1,cr,i,1});
cl=q[i].l;cr=q[i].r;
} memset(buc,0,sizeof(buc));
for(int i=1;i<=n;i++){
for(int j:v) buc[a[i]^j]++;
for(int j=0;j<vl[i].size();j++){
int l=vl[i][j].l,r=vl[i][j].r,id=vl[i][j].id;
ll sum=0;for(int t=l;t<=r;t++) sum+=buc[a[t]];
q[id].ans+=sum*vl[i][j].op;
}
} memset(buc,0,sizeof(buc));
for(int i=n;i;i--){
for(int j:v) buc[a[i]^j]++;
for(int j=0;j<vr[i].size();j++){
int l=vr[i][j].l,r=vr[i][j].r,id=vr[i][j].id;
ll sum=0;for(int t=l;t<=r;t++) sum+=buc[a[t]];
q[id].ans+=sum*vr[i][j].op;
}
}
for(int i=2;i<=qu;i++) q[i].ans+=q[i-1].ans;
for(int i=1;i<=qu;i++) anss[q[i].id]=q[i].ans;
for(int i=1;i<=qu;i++) printf("%lld\n",anss[i]);
return 0;
}
/*
6 1 0
1 2 3 1 2 3
1 6 6 5 1
1 2 3 4 5 6
1 5
1 6
2 5
2 6
3 6 14 5 1
1 2 3 4 5 6 7 1 2 3 4 5 6 7
1 14
2 13
3 9
1 12
4 11
*/

洛谷 P4887 -【模板】莫队二次离线(第十四分块(前体))(莫队二次离线)的更多相关文章

  1. P4887 第十四分块(前体) 莫队

    题意: 给你一个序列,每次询问l,r问多少个a[i]^a[j]有k个1,k固定. 序列长度1e5,a[i]<=2^14 时限1s,空间40M 题解: 个人其实开始没什么思路,看了题解也好久,题解 ...

  2. 洛谷P4887 第十四分块(前体)(二次离线莫队)

    题面 传送门 题解 lxl大毒瘤 我们考虑莫队,在移动端点的时候相当于我们需要快速计算一个区间内和当前数字异或和中\(1\)的个数为\(k\)的数有几个,而这个显然是可以差分的,也就是\([l,r]\ ...

  3. [洛谷P4887]第十四分块(前体)

    题目大意: 给定一个长度为\(n\)的序列\(a\),\(k\),和\(m\)次询问. 每次询问给定区间\([l,r]\),求满足\(l\leqslant i< j\leqslant r\)且\ ...

  4. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  5. 洛谷-P5357-【模板】AC自动机(二次加强版)

    题目传送门 -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题 sol:AC自动机,还是要解决跳fail边产生的重复访问,但 ...

  6. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  7. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  8. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

  9. 洛谷.1919.[模板]A*B Problem升级版(FFT)

    题目链接:洛谷.BZOJ2179 //将乘数拆成 a0*10^n + a1*10^(n-1) + ... + a_n-1的形式 //可以发现多项式乘法就模拟了竖式乘法 所以用FFT即可 注意处理进位 ...

随机推荐

  1. 在 Windows 10 上安装 Coq 库 Mathematical Components

    初学 Coq 时看的是 Mathematical Components 这本书,它自带了一个 Coq 的库,这是它的安装教程 这个库的安装要用到 OCaml Package Manager (OPAM ...

  2. Beta_Scrum Meeting_2

    会议概要 日期:2021年5月30日 出席人员:除zwh以外的所有人员 会议概述:讨论前两天工作进度以及后两天工作计划 人员分工 组员 负责 前两日完成的工作 后两日即将完成的工作 遇到的困难 hcc ...

  3. 【二食堂】Beta - Scrum Meeting 6

    Scrum Meeting 6 例会时间:5.19 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 实体标注的优化基本已经实现,后端有bug,还没有进行接口调用 issue 2 ...

  4. Hadoop的HA(ZooKeeper)安装与部署

    非HA的安装步骤 https://www.cnblogs.com/live41/p/15467263.html 一.部署设定 1.服务器 c1   192.168.100.105    zk.name ...

  5. (转)linux下错误的捕获:errno和strerror的使用,以及perror和strerror的区别

    经常在调用linux 系统api 的时候会出现一些错误,比方说使用open() write() creat()之类的函数有些时候会返回-1,也就是调用失败,这个时候往往需要知道失败的原因.这个时候使用 ...

  6. SpringBoot教程(学习资源)

    SpringBoot教程 SpringBoot–从零开始学SpringBoot SpringBoot教程1 SpringBoot教程2 --SpringBoot教程2的GitHub地址 SpringB ...

  7. Typora简介

    Typora是什么 Typora是一款支持实时预览的Markdown文本编辑器,拥有macOS.Windows.Linux三个平台的版本,并且完全免费. 下载地址:https://www.typora ...

  8. Go语言核心36讲(Go语言进阶技术十四)--学习笔记

    20 | 错误处理 (下) 在上一篇文章中,我们主要讨论的是从使用者的角度看"怎样处理好错误值".那么,接下来我们需要关注的,就是站在建造者的角度,去关心"怎样才能给予使 ...

  9. Kali安装Parallels Tools过程记录

    最近两天又参加了公司一年一度的网络安全劳动竞赛,之前用过的一个 Kali 忘记密码进不去了 -_- .重新安装了 Kali 2021.3a 之后发现 Parallels Tools 安装失败,记录了一 ...

  10. prometheus(3)之grafan可视化展现

    可视化UI界面Grafana的安装和配置 Grafana介绍 Grafana是一个跨平台的开源的度量分析和可视化工具,可以将采集的数据可视化的展示,并及时通知给告警接收方.它主要有以下六大特点: 1. ...