维护序列
线段树题目。此题的更新必须要更新到叶节点,否则的话,会出现错误。对于一个int范围内的数字,更新若干次(最多32次)后必然会变成0,那么此时在更新就没有意义了。那么我们可以用lazy标记,当某个区间的数字全部变为0后,我们将这个区间做上标记。那么这个区间就不可能在被更新,这样就可以提高效率,减去不必要的更新。对于将一个数字的二进制位最低位1变成0,在做树状数组题目的时候我们常用一个lowbit()函数来获取某个数字二进制位最低位1,这里我们也用这个来实现,我们先取出对应的最低位,然后在进行异或操作就可以了,也可以将取出的数字进行一次取反,然后在与原数字进行与操作。即:a&(~(a&(-a)))
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std ;
#define MAXN 10005
#define M(x , y) (x+y)>>1
#define L(x) x<<1
#define R(x) x<<1|1
struct Tree{
int l ;
int r ;
int sum ;
int lazy;
}tree[MAXN * 4] ;
int n ;
int m ;
inline void pushup(int c){
int l = L(c) ;
int r = R(c) ;
tree[c].sum = tree[l].sum ^ tree[r].sum ;
if(tree[l].lazy && tree[r].lazy)
tree[c].lazy = 1 ;
}
void build(int l ,int r , int c){
tree[c].l = l ;
tree[c].r = r ;
tree[c].sum = 0 ;
tree[c].lazy = 0 ;
if(l == r)
return ;
build( l , M(l, r) , L(c)) ;
build( (M(l , r)) + 1 , r , R(c)) ;
}
void insert(int v , int l , int c){
if(tree[c].l == l && tree[c].r==l){
tree[c].sum = v ;
if(!v)
tree[c].lazy = 1 ;
return ;
}
int m = M(tree[c].l , tree[c].r) ;
if(l <= m){
insert(v , l , L(c)) ;
}
else{
insert(v , l , R(c)) ;
}
pushup(c) ;
}
void update(int l , int r , int c){
if(tree[c].lazy)
return ;
if(l == r && tree[c].l==tree[c].r && l==tree[c].l){
if(tree[c].sum != 0){
int k = tree[c].sum & (-tree[c].sum) ;
tree[c].sum = tree[c].sum^k ;
if(!tree[c].sum){
tree[c].lazy = 1 ;
}
}
return ;
}
int m = M(tree[c].l , tree[c].r) ;
if(l==tree[c].l && r == tree[c].r){
update(l , m , L(c) ) ;
update(m + 1 , r , R(c)) ;
}
else if(m >= r){
update(l , r , L(c)) ;
}
else if(m < l){
update(l , r , R(c)) ;
}
else {
update(l , m , L(c)) ;
update(m+1 , r , R(c)) ;
}
pushup(c) ;
}
void query(int &ans , int l , int r , int c){
if(tree[c].lazy){
ans ^= 0 ;
return ;
}
if(tree[c].l == l && tree[c].r == r){
ans ^= tree[c].sum ;
return ;
}
int m = M(tree[c].l , tree[c].r) ;
if(r <= m){
query(ans , l , r , L(c)) ;
}
else if(l > m){
query(ans , l , r , R(c)) ;
}
else{
query(ans , l , m , L(c)) ;
query(ans , m + 1 , r , R(c)) ;
}
}
int main(){
while(scanf("%d%d" , &n , &m) != EOF){
int x ;
int y ;
int k ;
build(1 , n , 1) ;
for(int i = 1 ; i <= n ; i ++){
scanf("%d" , &x) ;
insert(x , i , 1 ) ;
}
for(int i = 1 ; i <= m ; i ++){
scanf("%d%d%d" , &k , &x , &y) ;
if(k == 1){
update(x , y , 1) ;
}
else{
int ans = 0 ;
query(ans , x , y , 1) ;
printf("%d\n" , ans) ;
}
}
}
return 0 ;
}