[整理]莫队二次离线

莫队二次离线用于处理移动区间端点时复杂度过大的问题。
以扩展区间 \([l,r]\)\([l,r+1]\) 为例,设多出的贡献为 \(f(r+1,[l,r])\),这个贡献必须是可以差分成 \(f(r+1,[1,r])-f(r+1,[1,l-1])\) 形式的。
到这里你当然可以把它们直接全部离线下来算贡献,但是你的空间复杂度会比较爆炸。让我们再来仔细观察这个东西,减号前面的部分可以简简单单预处理,后面的东西贡献的区间都是固定的,我们再把它离线一次。
和普通莫队一样需要分情况讨论,这里以从 \([l,r]\) 移动到 \([l,R]\)(其中 \(R\) 为查询区间端点)为例,我们计算出减号前的贡献,再在前缀 \(l-1\) 位置放一个查询 \([r+1,R]\) 表示计算这个区间的贡献。

if(R>r)q1[l-1].pub({r+1,R,i});//把询问离线到相应的位置
while(R>r)q[i].ans+=pre[++r];//顺便计算减号前贡献

对于其他几种情况是同理的,需要注意符号。
然后我们发现,在处理左端点移动时,会出现形如 \(f(l,[1,l])\) 的东西,我们没有处理过它,于是可以假装它是我们处理过的 \(f(l,[1,l-1])\)。而只有 \(k=0\) 时相等的元素会有影响,所以特判一下即可。
模板题核心代码(预处理那里运用了异或的一些性质):

const int N=200010;
int n,m,pp,a[N],bel[N],len,ans[N];
struct Query {
  int l,r,idx,ans;
}q[N];
bool operator < (Query A,Query B){
  return bel[A.l]==bel[B.l]?A.r<B.r:bel[A.l]<bel[B.l];
}
struct Query1 {
  int l,r,idx,sgn;
};
vector<Query1> q1[N];
vector<int> buc;
int b[N],pre[N];
signed main(){
  Read(n),Read(m),Read(pp),len=sqrt(n);
  for(rg int i=1;i<=n;i++)Read(a[i]);
  for(rg int i=1;i<=m;i++)Read(q[i].l),Read(q[i].r),q[i].idx=i;
  for(rg int i=1;i<=n;i++)bel[i]=(i-1)/len+1;
  sort(q+1,q+1+m);
  for(rg int i=0;i<=16384;i++){
    if(__builtin_popcount(i)==pp)buc.pub(i);
  }
  for(rg int i=1;i<=n;i++){
    pre[i]=b[a[i]];
    for(rg auto j:buc)b[a[i]^j]++;
  }
  for(rg int i=1,l=1,r=0;i<=m;i++){
    int L=q[i].l,R=q[i].r;
    if(L<l)q1[r].pub({L,l-1,i,1});
    while(L<l)q[i].ans-=pre[--l];
    if(L>l)q1[r].pub({l,L-1,i,-1});
    while(L>l)q[i].ans+=pre[l++];
    if(R>r)q1[l-1].pub({r+1,R,i,-1});
    while(R>r)q[i].ans+=pre[++r];
    if(R<r)q1[l-1].pub({R+1,r,i,1});
    while(R<r)q[i].ans-=pre[r--];
  }
  memset(b,0,sizeof(b));
  for(rg int i=1;i<=n;i++){
    for(rg auto j:buc)b[a[i]^j]++;
    for(rg auto j:q1[i]){
      for(rg int k=j.l;k<=j.r;k++){
        q[j.idx].ans+=j.sgn*(b[a[k]]-(k<=i&&!pp));
      }
    }
  }
  for(rg int i=1;i<=m;i++)q[i].ans+=q[i-1].ans;
  for(rg int i=1;i<=m;i++)ans[q[i].idx]=q[i].ans;
  for(rg int i=1;i<=m;i++)cout<<ans[i]<<endl;
  KafuuChino HotoKokoa
}
posted @ 2021-06-25 19:57  ajthreac  阅读(201)  评论(0编辑  收藏  举报