description:
给一个序列a 对a进行 区间求和 或者 区间异或的操作 每次输出区间求和的值
solution:
对于区间求和并且带有更新操作 就想到树状数组或者线段树,剩下的就是区间异或的操作,对于位运算,一般都按每一位来看,异或操作只有对应位不同才对答案有贡献,于是我们建立一个二维线段树,维护每一位的情况,ai的值和n范围都是1e5,需要的空间为 1e5 * 4 * 20 * 2,空间是够的,剩下就是对线段树的区间更新和查询操作了,最后算答案时候乘上对应的2次幂就好
code:
#include <bits/stdc++.h> using namespace std; #define LL long long const int N = 1e5 + 5; LL sum[N << 2][22],lazy[N << 2][22],a[N]; void pushup(int id,int v){//回溯时对父节点更新 sum[v][id] = sum[v << 1][id] + sum[v << 1 | 1][id]; } void pushdown(int id,int l,int r,int v){//lazy操作对子节点更新 if(lazy[v][id] == 0){ return ; } lazy[v << 1][id] ^= 1;//lazy标记往子节点传递 lazy[v << 1 | 1][id] ^= 1; int mid = l + r >> 1; sum[v << 1][id] = (mid - l + 1) - sum[v << 1][id];//异或取反操作 ^1 sum[v << 1 | 1][id] = (r - mid) - sum[v << 1 | 1][id]; lazy[v][id] = 0; } void build(int id,int l,int r,int v){//建树 if(l == r){ sum[v][id] = ((a[l] >> id)&1);//拆分每一位 lazy[v][id] ^= 1; return ; } int mid = l + r >> 1; build(id,l,mid,v << 1); build(id,mid + 1,r,v << 1 | 1); pushup(id,v); } void update(int id,int L,int R,int l,int r,int v){ if(L <= l && r <= R){ sum[v][id] = (r - l + 1) - sum[v][id];//异或取反操作 ^1 lazy[v][id] ^= 1; return ; } pushdown(id,l,r,v); int mid = l + r >> 1; if(L <= mid){ update(id,L,R,l,mid,v << 1); } if(R > mid){ update(id,L,R,mid + 1,r,v << 1 | 1); } pushup(id,v); } LL query(int id,int L,int R,int l,int r,int v){ if(L <= l && r <= R){ return sum[v][id] ; } LL res = 0; pushdown(id,l,r,v); int mid = l + r >> 1; if(L <= mid){ res += query(id,L,R,l,mid,v << 1); } if(R > mid){ res += query(id,L,R,mid + 1,r,v << 1 | 1); } pushup(id,v); return res; } int main(){ int n,q; scanf("%d%d",&n,&q); for(int i = 1;i <= n;i ++){ scanf("%lld",&a[i]); } for(int i = 0;i <= 20;i ++){ build(i,1,n,1);//对每一位建立线段树 维护每一位的和 } int l,r,k; while(q --){ int op; scanf("%d",&op); if(op == 1){ scanf("%d%d",&l,&r); LL res = 0; for(int i = 0;i <= 20;i ++){ res += 1LL*query(i,l,r,1,n,1)*(1LL << i);//查询答案对应二次幂 } printf("%lld\n",res); }else{ scanf("%d%d%d",&l,&r,&k); for(int i = 0;i <= 20;i ++){//对每一位进行更新操作 if((k >> i) & 1){//当前位为1 update(i,l,r,1,n,1); } } } } return 0; }