codechef Chef And Easy Xor Queries

拟墨画扇 提交于 2020-03-22 20:04:14

做法:我们考虑前缀异或和,修改操作就变成了区间[i,n]都异或x

查询操作就变成了:区间[1,x]中有几个k

显然的分块,每个块打一个tag标记表示这个块中所有的元素都异或了tag[x]

然后处理出这个块中每种数的个数

注意查询的时候零散的块要下放标记

代码:

#include<bits/stdc++.h>
#define N 100005
#define M 334
using namespace std;
int cnt[M][N*14],sum[N],tag[M],ll[M],rr[M],a[N];
int n,Q,opt,x,y,block,num;
inline int gt(int x){return (x-1)/block+1;}
inline void pushdown(int x){
	if (!tag[x]) return;
	for (int i=ll[x];i<=rr[x];i++){
		cnt[x][sum[i]]--;
		sum[i]^=tag[x];
		cnt[x][sum[i]]++;
	}
	tag[x]=0;
}
inline void query(int x,int y,int k){
	//printf("%d %d\n",gt(x),gt(y));
	int ans=0;
	pushdown(gt(x));pushdown(gt(y));
	if (gt(x)+1>=gt(y)){
		for (int i=x;i<=y;i++) if (sum[i]==k) ans++;
	}
	else {
		for (int i=x;i<=rr[gt(x)];i++) if (sum[i]==k) ans++;
		for (int i=ll[gt(y)];i<=y;i++) if (sum[i]==k) ans++;
		for (int j=gt(x)+1;j<gt(y);j++) ans+=cnt[j][k^tag[j]];
	}
	printf("%d\n",ans);
}
inline void change(int x,int y,int z){
	int tmp=z;z=z^a[x];a[x]=tmp;
	if (gt(x)+1>=gt(y)){
		for (int i=x;i<=y;i++){
			cnt[gt(i)][sum[i]]--;
			sum[i]^=z;
			cnt[gt(i)][sum[i]]++;
		}
	}
	else {
		for (int i=x;i<=rr[gt(x)];i++){
			cnt[gt(i)][sum[i]]--;
			sum[i]^=z;
			cnt[gt(i)][sum[i]]++;
		}
		for (int i=ll[gt(y)];i<=y;i++){
			cnt[gt(i)][sum[i]]--;
			sum[i]^=z;
			cnt[gt(i)][sum[i]]++;
		}
		for (int j=gt(x)+1;j<gt(y);j++) tag[j]^=z;
	}
	//for (int i=1;i<=n;i++) printf("%d %d\n",sum[i],tag[i]);
}
int main(){
	scanf("%d%d",&n,&Q);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i];
	block=(int)sqrt(n);num=n/block;if (n%block) num++;
	for (int i=1;i<=num;i++) ll[i]=(i-1)*block+1,rr[i]=i*block;rr[num]=n;
	//for (int i=1;i<=num;i++) printf("%d %d\n",ll[i],rr[i]);
	for (int i=1;i<=num;i++)
		for (int j=ll[i];j<=rr[i];j++) cnt[i][sum[j]]++;
	while (Q--){
		scanf("%d%d%d",&opt,&x,&y);
		if (opt==2) query(1,x,y);
		else change(x,n,y);
	}
	return 0;
} 

  

  1. #include<bits/stdc++.h>
  2. #define N 100005
  3. #define M 334
  4. using namespace std;
  5. int cnt[M][N*14],sum[N],tag[M],ll[M],rr[M],a[N];
  6. int n,Q,opt,x,y,block,num;
  7. inline int gt(int x){return (x-1)/block+1;}
  8. inline void pushdown(int x){
  9. if (!tag[x]) return;
  10. for (int i=ll[x];i<=rr[x];i++){
  11. cnt[x][sum[i]]--;
  12. sum[i]^=tag[x];
  13. cnt[x][sum[i]]++;
  14. }
  15. tag[x]=0;
  16. }
  17. inline void query(int x,int y,int k){
  18. //printf("%d %d\n",gt(x),gt(y));
  19. int ans=0;
  20. pushdown(gt(x));pushdown(gt(y));
  21. if (gt(x)+1>=gt(y)){
  22. for (int i=x;i<=y;i++) if (sum[i]==k) ans++;
  23. }
  24. else {
  25. for (int i=x;i<=rr[gt(x)];i++) if (sum[i]==k) ans++;
  26. for (int i=ll[gt(y)];i<=y;i++) if (sum[i]==k) ans++;
  27. for (int j=gt(x)+1;j<gt(y);j++) ans+=cnt[j][k^tag[j]];
  28. }
  29. printf("%d\n",ans);
  30. }
  31. inline void change(int x,int y,int z){//[x,y]����^z
  32. int tmp=z;z=z^a[x];a[x]=tmp;
  33. if (gt(x)+1>=gt(y)){
  34. for (int i=x;i<=y;i++){
  35. cnt[gt(i)][sum[i]]--;
  36. sum[i]^=z;
  37. cnt[gt(i)][sum[i]]++;
  38. }
  39. }
  40. else {
  41. for (int i=x;i<=rr[gt(x)];i++){
  42. cnt[gt(i)][sum[i]]--;
  43. sum[i]^=z;
  44. cnt[gt(i)][sum[i]]++;
  45. }
  46. for (int i=ll[gt(y)];i<=y;i++){
  47. cnt[gt(i)][sum[i]]--;
  48. sum[i]^=z;
  49. cnt[gt(i)][sum[i]]++;
  50. }
  51. for (int j=gt(x)+1;j<gt(y);j++) tag[j]^=z;
  52. }
  53. //for (int i=1;i<=n;i++) printf("%d %d\n",sum[i],tag[i]);
  54. }
  55. int main(){
  56. scanf("%d%d",&n,&Q);
  57. for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i];
  58. block=(int)sqrt(n);num=n/block;if (n%block) num++;
  59. for (int i=1;i<=num;i++) ll[i]=(i-1)*block+1,rr[i]=i*block;rr[num]=n;
  60. //for (int i=1;i<=num;i++) printf("%d %d\n",ll[i],rr[i]);
  61. for (int i=1;i<=num;i++)
  62. for (int j=ll[i];j<=rr[i];j++) cnt[i][sum[j]]++;
  63. while (Q--){
  64. scanf("%d%d%d",&opt,&x,&y);
  65. if (opt==2) query(1,x,y);
  66. else change(x,n,y);
  67. }
  68. return 0;
  69. }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!