离线二次莫队

洛谷P4887 第十四分块(前体)

考虑莫队计算答案,显然对区间询问可以转化成对前缀计算对某个值的贡献查询$O(n \sqrt{n})$次。

把莫队中的查询离线计算,从前往后推算,可以在$O(C(14,7))$中修改,$O(1)$查询。

由于修改$O(n)$次,查询$O(n \sqrt{n})$次,复杂度$O(n \sqrt{n}+C(14,7)n)$。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int N=100005,M=16384,W=350;
int n,m,k,tp,stk[3433],a[N],c[N];ll p1[N],p2[N],res[N<<1],ans[N]; 
struct st{int l,r,i;}q[N];vector<st>g[N]; 
inline bool cmp(st a,st b){return a.l/W^b.l/W?a.l<b.l:a.r<b.r;}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++){scanf("%d%d",&q[i].l,&q[i].r);q[i].i=i;}
    for(int i=0;i<M;i++)
    {
        int c=0;for(int j=0;j<14;j++)c+=i>>j&1;
        if(c==k)stk[++tp]=i;
    }
    sort(q+1,q+m+1,cmp);int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        if(l<q[i].l)g[r].pb((st){l,q[i].l-1,i<<1});else if(l>q[i].l)g[r].pb((st){q[i].l,l-1,i<<1});l=q[i].l;
        if(r<q[i].r)g[l-1].pb((st){r+1,q[i].r,i<<1|1});else if(r>q[i].r)g[l-1].pb((st){q[i].r+1,r,i<<1|1});r=q[i].r;
    }
    for(int i=1;i<=n;i++)
    {
        p1[i]=p1[i-1]+c[a[i]];
        for(int j=1;j<=tp;j++)c[a[i]^stk[j]]++;
        p2[i]=p2[i-1]+c[a[i]];
        for(int j=0;j<g[i].size();j++)
        {
            st t=g[i][j];
            for(int k=t.l;k<=t.r;k++)res[t.i]+=c[a[k]];
        } 
    }
    l=1,r=0;ll s=0;
    for(int i=1;i<=m;i++)
    {
        if(l<q[i].l)s+=p2[q[i].l-1]-p2[l-1]-res[i<<1];else if(l>q[i].l)s+=res[i<<1]+p2[q[i].l-1]-p2[l-1];l=q[i].l;
        if(r<q[i].r)s+=p1[q[i].r]-p1[r]-res[i<<1|1];else if(r>q[i].r)s+=res[i<<1|1]-p1[r]+p1[q[i].r];r=q[i].r;ans[q[i].i]=s;
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
} 
//        while(l<q[i].l){g[r].push_back((st){l,-1,i});g[l].push_back((st){l,1,i});l++;}
//        while(l>q[i].l){l--;g[r].push_back((st){l,1,i});g[l].push_back((st){l,-1,i});}
//        while(r<q[i].r){r++;g[r-1].push_back((st){r,1,i});g[l-1].push_back((st){r,-1,i});}
//        while(r>q[i].r){g[r-1].push_back((st){r,-1,i});g[l-1].push_back((st){r,1,i});r--;}

洛谷P5398 [Ynoi2018]GOSICK

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int N=100005,M=100000,W=500;
int n,m,a[N],b[N],c[N],ss[N],r1[N],r2[N],r3[N],r4[N];ll p1[N],p2[N],res[N<<1],ans[N]; 
struct st{int l,r,i;}q[N];vector<st>g[N];vector<int>V[N];
inline bool cmp(st a,st b){return a.l/W^b.l/W?a.l<b.l:a.r<b.r;}
inline void init()
{
    for(int i=1;i<=M;i++)for(int j=i;j<=M;j+=i)V[j].pb(i);
    for(int i=1;i<=M;i++)for(int j=1;j<=32;j++)if(i%j==0)ss[i]|=1<<j-1;
}
void ins(int x)
{
    if(x<=32)
    {
        if(x<=8)for(int i=0;i<256;i++)r1[i]+=(i>>(x-1)&1);
        else if(x<=16)for(int i=0;i<256;i++)r2[i]+=(i>>(x-9)&1);
        else if(x<=24)for(int i=0;i<256;i++)r3[i]+=(i>>(x-17)&1);
        else for(int i=0;i<256;i++)r4[i]+=(i>>(x-25)&1);
    }
    else for(int i=x;i<=M;i+=x)b[i]++;
}
inline int calc(int x){x=ss[x];return r1[x&255]+r2[x>>8&255]+r3[x>>16&255]+r4[x>>24&255];}
inline int sum(int x){return b[x]+c[x]+calc(x);}
int main()
{
    scanf("%d%d",&n,&m);init();
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++){scanf("%d%d",&q[i].l,&q[i].r);q[i].i=i;}
    sort(q+1,q+m+1,cmp);int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        if(l<q[i].l)g[r].pb((st){l,q[i].l-1,i<<1});else if(l>q[i].l)g[r].pb((st){q[i].l,l-1,i<<1});l=q[i].l;
        if(r<q[i].r)g[l-1].pb((st){r+1,q[i].r,i<<1|1});else if(r>q[i].r)g[l-1].pb((st){q[i].r+1,r,i<<1|1});r=q[i].r;
    }
    for(int i=1;i<=n;i++)
    {
        p1[i]=p1[i-1]+sum(a[i]);
        for(int j=0;j<V[a[i]].size();j++)c[V[a[i]][j]]++;
        ins(a[i]);p2[i]=p2[i-1]+sum(a[i]);
        for(int j=0;j<g[i].size();j++){st t=g[i][j];for(int k=t.l;k<=t.r;k++)res[t.i]+=sum(a[k]);} 
    }
    l=1,r=0;ll s=0;
    for(int i=1;i<=m;i++)
    {
        if(l<q[i].l)s+=p2[q[i].l-1]-p2[l-1]-res[i<<1];else if(l>q[i].l)s+=res[i<<1]+p2[q[i].l-1]-p2[l-1];l=q[i].l;
        if(r<q[i].r)s+=p1[q[i].r]-p1[r]-res[i<<1|1];else if(r>q[i].r)s+=res[i<<1|1]-p1[r]+p1[q[i].r];r=q[i].r;ans[q[i].i]=s+r-l+1;
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
} 
posted @ 2019-06-11 18:41  alonefight  阅读(79)  评论(0编辑  收藏  举报