zoukankan      html  css  js  c++  java
  • [整理]莫队二次离线

    莫队二次离线用于处理移动区间端点时复杂度过大的问题。
    以扩展区间 ([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
    }
    
    内容来自_ajhfff_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    前端框架framework和库library的一点区别和记录
    DButils实现数据库表下划线转bean中驼峰格式
    layui内部使用jQuery
    Object...与Object[]使用的一点区别和记录
    SSM框架整合系列——第一步
    $.ajax的async设置true和false的区别一点笔记
    idea使用破解版mybatis plugin插件失败,idea打不开的解决方案
    ECharts在柱状图的柱子上方显示数量的方法
    Echarts使用Ajax异步获得数据的前端json格式转化问题
    Ajax的post表单,不在url后接一大串参数键值对的方法
  • 原文地址:https://www.cnblogs.com/juruoajh/p/14924065.html
Copyright © 2011-2022 走看看