CC DEC.17 Chef And Easy Xor Queries 分块+懒标记

来源:互联网 发布:淘宝服装代购 编辑:程序博客网 时间:2024/06/06 18:12
题意:长度为n的序列a,Q次操作,操作1:(i,x)将第a[i]变为x. 操作2:(i,k) 问有多少个前缀j(j<=r)其异或和为k.
n,Q<=1e5,a[i],x,k<=1e6.


暴力的话 每次单点修改a[i],都要修改pre[j](j>=i)的前缀和.每次查询都要查询每个pre[i](i<=r) O(n*Q).

现在对pre来分块.每块维护cnt[i][x]:该块pre值为x的有多少个.

修改一个a[i]->y.
对于每一块,每个x出现cnt次 则现在变为x^a[i]^y 出现cnt次
1<=x<=1e5,不能对块内元素一个一个更新次数 则对每块都加上一个标记val[i],表示该块内每个pre真实值为pre[j]^val[i].
非整块的点 直接修改它的pre值和cnt值即可.

对于查询 非整块直接查询 注意其真实值为pre[i]^val[pos[i]] O(N*sqrt(N)).

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=120000,M=350;int n,Q,a[N],op,p,r,k,x,pre[N],val[N],m,num,pos[N];int cnt[M][N*10];void init(){m=(int)sqrt(n),num=n/m;if(n%m)num++;for(int i=1;i<=n;i++)pos[i]=(i-1)/m+1,val[i]=0;for(int i=1;i<=num;i++)for(int j=(i-1)*m+1;j<=n&&j<=i*m;j++)cnt[i][pre[j]]++;}int main(){scanf("%d%d",&n,&Q);for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=pre[i-1]^a[i];init();while(Q--){scanf("%d",&op);if(op==1){scanf("%d%d",&p,&x);for(int i=p;i<=pos[p]*m;i++){cnt[pos[p]][pre[i]]--;cnt[pos[p]][pre[i]^a[p]^x]++;pre[i]=pre[i]^a[p]^x;}for(int i=pos[p]+1;i<=num;i++)val[i]=val[i]^a[p]^x;a[p]=x;}else{scanf("%d%d",&r,&k);//for(int i=1;i<=n;i++)//cout<<i<<' '<<(pre[i]^val[pos[i]])<<endl;int res=0;for(int i=1;i<=pos[r]-1;i++)res+=cnt[i][k^val[i]];for(int i=(pos[r]-1)*m+1;i<=r;i++)if((pre[i]^val[pos[i]])==k)res++;printf("%d\n",res);}}return 0;} 



原创粉丝点击