P4887 第十四分块(前体)

P4887 第十四分块(前体)

链接

P4887 第十四分块(前体)

题解

二次离线莫队。。新技能get。。
用于可以使用莫队且单次转移的效率不是 \(O(1)\) 的情况。
对于每次指针移动,先不直接算,而是把询问差分然后再次离线询问。
这样可以算出每一问对于上一个询问的答案的变化量,最后再重新按末对的顺序加起来就可以。

\(Code\)

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void print(LL x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n,m,K,B; 
int a[N],be[N];
struct query{
    int l,r,id;
}q[N];
bool cmp(query x,query y){
    if(be[x.l]!=be[y.l]) return be[x.l]<be[y.l];
    return x.r<y.r;
}
//pre[x][0]=f(x,[1,x-1]) pre[x][1]=f(x,[1,x])
LL pre[N][2],s[N];
LL ans[N];
vector<int> c;
struct P{
    int l,r,id,f;
    P(int lx=0,int rx=0,int idx=0,int fx=0){
        l=lx;r=rx;id=idx;f=fx;
    }
};
vector<P> ve[N];
int main(){
    scanf("%d%d%d",&n,&m,&K);B=sqrt(n);
    for(int i=1;i<=n;++i) {
        scanf("%d",&a[i]);
        be[i]=(i+B-1)/B;
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    for(int i=0;i<16384;++i) 
        if(__builtin_popcount(i)==K) c.push_back(i);
    for(int i=1;i<=n;++i){
        for(int j=0;j<c.size();++j) ++s[a[i]^c[j]];
        pre[i+1][0]=s[a[i+1]];pre[i][1]=s[a[i]];
    }
    memset(s,0,sizeof(s));
    int l=1,r=0;
    for(int i=1;i<=m;++i){
        if(r<q[i].r) ve[l-1].push_back(P(r+1,q[i].r,q[i].id,-1));
        while(r<q[i].r){++r;ans[q[i].id]+=pre[r][0];} 
        //r++ f(x,[l,x-1])=f(x,[1,x-1])-f(x,[1,l-1])
        if(l>q[i].l) ve[r].push_back(P(q[i].l,l-1,q[i].id,1));
        while(l>q[i].l){--l;ans[q[i].id]-=pre[l][1];}
        //l-- f(x,[x+1,r])=f(x,[1,r])-f(x,[1,x])
        if(r>q[i].r) ve[l-1].push_back(P(q[i].r+1,r,q[i].id,1));
        while(r>q[i].r){ans[q[i].id]-=pre[r][0];--r;} 
        //r-- -f(x,[l,x-1])=-f(x,[1,x-1])+f(x,[1,l-1])
        if(l<q[i].l) ve[r].push_back(P(l,q[i].l-1,q[i].id,-1));
        while(l<q[i].l){ans[q[i].id]+=pre[l][1];++l;}
        //l++ -f(x,[x+1,r])=-f(x,[1,r])+f(x,[1,x])
    }
    for(int i=1;i<=n;++i){
        for(int j=0;j<c.size();++j) ++s[a[i]^c[j]];
        for(int j=0;j<ve[i].size();++j){
            for(int k=ve[i][j].l;k<=ve[i][j].r;++k){
                ans[ve[i][j].id]+=(LL)ve[i][j].f*s[a[k]];
            }
        }
    }
    for(int i=2;i<=m;++i){
        ans[q[i].id]+=ans[q[i-1].id]; 
    }
    for(int i=1;i<=m;++i) {
        print(ans[i]);
        puts("");
    }
    return 0;
}
posted @ 2020-08-17 18:29  Iscream-2001  阅读(109)  评论(0编辑  收藏  举报
/* */