给定1e5个数ai
操作1,求区间和
操作2,将ql,qr区间内所有数与x异或
线段树真神奇。。。。 将ai的每一位用线段树表示,20个线段树即可。
//又是1e5和线段树
//1.r - l + 1
//2.pushdown时lc,rc要取反
//3.bitset<20>打成10
//4.seg,lazy线段树居然没有开<< 2
#include
#include
#include
using namespace std;
#define mid (l + r) / 2
#define lc (rt << 1)
#define rc (rt << 1 | 1)
const int maxn = 1e5 + 5;
typedef long long ll;
int seg[maxn << 2][20];//seg[x][q]表示第q棵树,为了和a的坐标对应
int lazy[maxn << 2][20];//区间修改
bitset<20> a[maxn];//0是低位
bitset<20>x;
int ql,qr;
ll weight[20];
int id;
void init(int l,int r,int rt)//是query的时候再乘上2^i位权好了
{
if(l == r){seg[rt][id] = a[l][id];return;}
init(l, mid, lc);
init(mid + 1, r, rc);
seg[rt][id] = seg[lc][id] + seg[rc][id];
}
void pushdown(int l,int r,int rt)
{
if(lazy[rt][id])
{
lazy[lc][id] ^= 1;//这里是取反
lazy[rc][id] ^= 1;
seg[lc][id] = (mid - l + 1) - seg[lc][id];
seg[rc][id] = (r - mid) - seg[rc][id];
lazy[rt][id] = 0;
}
}
int query(int l,int r,int rt)//记录的是第id位上,1的个数
{
if(ql <= l && r <= qr) {
return seg[rt][id];
}
pushdown(l, r, rt);
int ans = 0;
if(ql <= mid) ans += query(l, mid, lc);
if(mid < qr) ans += query(mid + 1, r, rc);
return ans;
}
void update(int l,int r,int rt)
{
if(ql <= l && r <= qr){
lazy[rt][id] ^= 1;//取反
seg[rt][id] = (r - l + 1) - seg[rt][id];//
return;
}
pushdown(l,r,rt);
if(ql <= mid) update(l, mid, lc);
if(mid < qr) update(mid + 1, r, rc);
seg[rt][id] = seg[lc][id] + seg[rc][id];
}
int main()
{
int n,tmp;
scanf("%d",&n);
for (int i = 1; i <= n; i ++) {
scanf("%d",&tmp);
a[i] = tmp;
}
for (id = 0; id < 20; id ++) {
init(1, n, 1);
weight[id] = (1ll << id);
}
int m;scanf("%d",&m);
int op;
for (int i = 0; i < m; i ++) {//如果每个树里只存储0,1,而不计算位权,那么是不会超int的,query int ok
scanf("%d%d%d",&op,&ql,&qr);
if(ql > qr) swap(ql, qr);
if(op == 1){
ll sum = 0;
for (id = 0; id < 20; id ++) {
sum += (ll)query(1, n, 1) * weight[id];
}
printf("%lld\n",sum);
}
else{
scanf("%d",&tmp);
x = tmp;
for (id = 0; id < 20; id ++) {
if(x[id]) update(1, n, 1);//只有该位为1时,才会改变
}
}
}
return 0;
}