https://www.luogu.org/problemnew/show/P2846
好多题解用线段树来写,然而分块不是更简单好些吗?
一个数组use记录这一块进行了多少次开关操作,两边单独计算,注意每次更新两边是也要维护这一块。
查询两边暴力加减,块内循环枚举。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int n,m,k,bl[100006],f[100006],a[100006],use[100006]; void Xor(int l,int r) { for(int i=l;i<=min(bl[l]*k,r);i++)f[bl[i]]+=a[i]^use[bl[i]]?-1:1,a[i]^=1; if(bl[l]!=bl[r])for(int i=(bl[r]-1)*k+1;i<=r;i++)f[bl[i]]+=a[i]^use[bl[i]]?-1:1,a[i]^=1; for(int i=bl[l]+1;i<bl[r];i++)use[i]^=1,f[i]=k-f[i]; } int query(int l,int r) { int ans=0; for(int i=l;i<=min(r,bl[l]*k);i++)ans+=a[i]^use[bl[i]]; if(bl[l]!=bl[r])for(int i=(bl[r]-1)*k+1;i<=r;i++)ans+=a[i]^use[bl[i]]; for(int i=bl[l]+1;i<bl[r];i++)ans+=f[i]; return ans; } int main() { int x,y,z; scanf("%d%d",&n,&m); k=sqrt(n); for(int i=1;i<=n;i++)bl[i]=(i-1)/k+1; for(int i=1;i<=m;i++) { scanf("%d%d%d",&z,&x,&y); if(z==0)Xor(x,y); else printf("%d ",query(x,y)); } }