离线二次莫队
洛谷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; }