传送门:>Here<
给出一个长度为\(n\)的序列\(a\),\(m\)次询问:一,询问区间和;二,区间异或上一个数\(x\)。(\(n,m \leq 10^5\),\(a_i,x \leq 10^6\))
解题思路
这是一个用线段树来维护区间位运算的问题。
首先将\(a_i\)全都看成二进制。二进制求和还有一种思路:不进位的二进制加法,即累积二进制的每一位上1的个数。线段树上每一个节点保存\(\log a_i\)个值,表示区间内某一位上1的个数和
。这样就可以做区间位运算了。这道题中是异或,那么已知区间长度为\(r-l+1\),对于需要异或1的那一位,\(cnt_i \rightarrow (r-l+1)-cnt_i\)。
\(Code\)
我一般采用的\(pushdown\)是先将当前节点的值更新并打上懒标。因此懒标只对它一下的点起作用。
/*DennyQi 2019*/
#include
#include
#include
#include
#define int long long
using namespace std;
const int N = 100010;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
inline int mul(const int& a, const int& b){ return 1ll*a*b%P; }
inline int add(const int& a, const int& b){ return (a+b>=P)?a+b-P:a+b; }
inline int sub(const int& a, const int& b){ return (a-b<0)?a-b+P:a-b; }
inline int read(){
int x(0),w(1); char c = getchar();
while(c^'-' && (c<'0' || c>'9')) c = getchar();
if(c=='-') w = -1, c = getchar();
while(c>='0' && c<='9') x = (x<<3)+(x<<1)+c-'0', c = getchar();
return x*w;
}
int n,m,opt,x,y,z,a[N],v[N<<2][21],tag[N<<2];
inline void pushup(int u){
for(int i = 0; i <= 20; ++i){
v[u][i] = v[u<<1][i] + v[u<<1|1][i];
}
}
void build(int u, int l, int r){
if(l == r){
int j = 0;
while(a[l] > 0){
v[u][j] = (a[l] & 1);
++j;
a[l] >>= 1;
}
return;
}
int mid = (l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
inline void xor_(int u, int l, int r, int k){
for(int i = 0; i <= 20; ++i){
int b = (k & 1);
k >>= 1;
if(b){
v[u][i] = (r-l+1) - v[u][i];
}
}
}
inline void pushdown(int u, int l, int r){
if(!tag[u]) return;
int mid = (l+r)>>1;
xor_(u<<1,l,mid,tag[u]);
xor_(u<<1|1,mid+1,r,tag[u]);
tag[u<<1] ^= tag[u];
tag[u<<1|1] ^= tag[u];
tag[u] = 0;
}
int query(int u, int l, int r, int x, int y){
if(l > y || r < x) return 0;
if(x <= l && r <= y){
int res = 0;
for(int i = 0; i <= 20; ++i){
res += (1<>1;
return query(u<<1,l,mid,x,y) + query(u<<1|1,mid+1,r,x,y);
}
void modify(int u, int l, int r, int x, int y, int k){
if(l > y || r < x) return;
if(x <= l && r <= y){
tag[u] ^= k;
xor_(u,l,r,k);
return;
}
pushdown(u,l,r);
int mid = (l+r)>>1;
modify(u<<1,l,mid,x,y,k);
modify(u<<1|1,mid+1,r,x,y,k);
pushup(u);
}
signed main(){
// freopen("file.in","r",stdin);
n = read();
for(int i = 1; i <= n; ++i){
a[i] = read();
}
build(1,1,n);
m = read();
while(m--){
opt = read();
if(opt == 1){
x = read(), y = read();
printf("%lld\n",query(1,1,n,x,y));
}else{
x = read(), y = read(), z = read();
modify(1,1,n,x,y,z);
}
}
return 0;
}