这就是棵裸的线段树,我一下就切掉了。话说最近考了好多好多道线duang树啊!感觉我自己都被duang掉了。
由于异或不满足分配律,不能像矩阵那题一样直接对和进行异或操作。而异或是满足结合律的,于是我们可以对于多个异或标记进行合并。
我们抓住异或的本质(别说抓不住),异或x就是如果x二进制的某一位是1,就将被异或的那个数的那一位1变成0,0变成1。我们就在线段树的叶子开一个大小为20左右的数组,记录二进制下每一位是0是1。然后向上维护每一位的和。我们知道一段区间的1个个数就是和,0的个数就是区间长度减去和。我们对这段区间异或x,将x分解,有一位是1,代表将这段区间的每一个数的1变0,0变1,再求和。其实和就变成了区间长度减去和了。于是和就可以进行区间信息加法了。
然后将懒惰标记lazy合并后向下传,和也照样维护,到底端就变成了那一位是0是1了。查询的时候再将对应的位的权乘和累加起来,然后这题就这样的过了。
时间的话,多一个20倍的常数,然而题目良心,操作不多,所以不虚。
ps:这题的数据有毒??我暴力跟正解拍了半天没出错,正解一交AC了,暴力却只有20分,WA了一堆,真是让我长见识了!另外有人的暴力拿了50分,一问,答曰:我的线段树的标记是down到底的,太强大了!我震惊得说不出话来,此处省略rand()+1字。
#include
#include
#include
#include
#include
#include
#define maxn 100010
using namespace std;
typedef long long LL;
int n, m, a[maxn];
struct Tnode{
int num[22];
int lazy;
}tree[maxn<<2];
void build(int root, int L, int R){
if(L == R){
int temp = a[L], t = 0;
while(temp){
tree[root].num[t] = temp & 1;
t ++;
temp >>= 1;
}
tree[root].lazy = 0;
return;
}
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
build(Lson, L, mid);
build(Rson, mid+1, R);
for(int i = 0; i <= 20; i++)
tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i];
tree[root].lazy = 0;
}
void Down(int root, int L, int R){
if(!tree[root].lazy) return;
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
int temp = tree[root].lazy, t = 0;
while(temp){
if(temp & 1){
tree[Lson].num[t] = (mid - L + 1) - tree[Lson].num[t];
tree[Rson].num[t] = (R - mid) - tree[Rson].num[t];
}
t ++;
temp >>= 1;
}
tree[Lson].lazy ^= tree[root].lazy;
tree[Rson].lazy ^= tree[root].lazy;
tree[root].lazy = 0;
}
void update(int root, int L, int R, int x, int y, int v){
if(x > R || y < L) return;
if(x <= L && y >= R){
int temp = v, t = 0;
while(temp){
if(temp & 1) tree[root].num[t] = (R - L + 1) - tree[root].num[t];
t ++;
temp >>= 1;
}
tree[root].lazy ^= v;
return;
}
Down(root, L, R);
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
update(Lson, L, mid, x, y, v);
update(Rson, mid+1, R, x, y, v);
for(int i = 0; i <= 20; i++)
tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i];
}
LL query(int root, int L, int R, int x, int y){
if(x > R || y < L) return 0LL;
if(x <= L && y >= R){
LL ans = 0LL;
for(int i = 0; i <= 20; i++) ans += (1LL << i) * tree[root].num[i];
return ans;
}
Down(root, L, R);
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
LL temp1 = query(Lson, L, mid, x, y);
LL temp2 = query(Rson, mid+1, R, x, y);
return temp1 + temp2;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, 1, n);
scanf("%d", &m);
int t, l, r, x;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &t, &l, &r);
if(t == 1)
printf("%lld\n", query(1, 1, n, l, r));
else{
scanf("%d", &x);
update(1, 1, n, l, r, x);
}
}
return 0;
}