题目
链接:https://ac.nowcoder.com/acm/contest/6046/C
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
在心理疏导室中有一种奇特的疏导工具,叫做红球。红球被提前分为了许多正方形小方格。
每当有人来找ATB做心理疏导时,ATB就会让他去先玩红球,然后通过红球小格方的高度来判断一个人的压力程度的高低
具体地讲,ATB会让该人对于一个序列执行以下操作
l,r
,输出 ∑ i = l r a i \sum_{i=l}^{r}a_i ∑i=lrail,r,k
,对于 l ≤ i ≤ r l ≤ i ≤ r l≤i≤r,将 x i x_i xi变为 x i ⊕ k x_i⊕k xi⊕k输入描述:
第一行两个整数n和m,表示数列长度和询问次数
第二行有 n n n个整数,表示这个数列的初始数值
接下来有 m m m行,形如 1 l r
或者 2 l r k
分别表示查询 ∑ i = l r a i \sum_{i=l}^{r}a_i ∑i=lrai
或者对于 l ≤ i ≤ r l ≤ i ≤ r l≤i≤r,将 x i x_i xi变为 x i ⊕ k x_i⊕k xi⊕k
输出描述:
对于每一个查询操作,输出查询的结果并换行
输入
10 10
8 5 8 9 3 9 8 3 3 6
2 1 4 1
1 2 6
2 9 10 8
1 1 7
2 4 7 8
2 8 8 6
2 2 3 0
1 1 2
2 9 10 4
1 2 3
输出
33
50
13
13
备注:
题解:
将数字拆成20个线段树
这样就变成计算区间异或1,和求区间1的个数
码力题
#include
#define ll long long
using namespace std;
const int S = 21;
const int MAXN = 1e5 + 4;
struct node{
int tag;
int v;
}tr[MAXN*4][S];
int n,m;
int o[MAXN];
void update(int k){
for(int i=0;i<S;i++){
tr[k][i].v = tr[k<<1][i].v + tr[k<<1|1][i].v;
}
}
void build(int k,int l,int r){
if(l==r){
int vn = o[l];
for(int i=0;i<S;i++){
tr[k][i].v = vn % 2;
vn /= 2;
}
return ;
}
int mid=(l+r)/2;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
void changeI(int k,int v,int sum){
for(int i=0;i<S;i++){
if(v%2==1){
tr[k][i].v=sum-tr[k][i].v;
}
tr[k][i].tag ^= v % 2;
v /= 2;
}
}
void push(int k,int i,int sum){
tr[k][i].tag = 0;
tr[k<<1][i].tag ^= 1;
tr[k<<1|1][i].tag ^= 1;
int sl=sum-sum/2;
int sr=sum/2;
tr[k<<1][i].v=sl - tr[k<<1][i].v;
tr[k<<1|1][i].v = sr - tr[k<<1|1][i].v;
}
void change(int k,int l,int r,int a,int b,int v){
if(l==a && r==b){
changeI(k,v,r-l+1);
return ;
}
for(int i=0;i<S;i++)if(tr[k][i].tag)push(k,i,r-l+1);
int mid=(l+r)/2;
if(b <= mid){
change(k<<1,l,mid,a,b,v);
} else if (a > mid){
change(k<<1|1,mid+1,r,a,b,v);
} else {
change(k<<1,l,mid,a,mid,v);
change(k<<1|1,mid+1,r,mid+1,b,v);
}
update(k);
}
ll calc(int k){
ll res = 0 , bs = 1;
for(int i=0;i<S;i++){
res += bs * tr[k][i].v;
bs *= 2;
}
return res;
}
ll ask(int k,int l,int r,int a,int b){
if(l==a && r==b){
return calc(k);
}
for(int i=0;i<S;i++)if(tr[k][i].tag)push(k,i,r-l+1);
int mid=(l+r)/2;
if(b<=mid){
return ask(k<<1,l,mid,a,b);
}else if(a > mid){
return ask(k<<1|1,mid+1,r,a,b);
}else{
return ask(k<<1,l,mid,a,mid) + ask(k<<1|1,mid+1,r,mid+1,b);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&o[i]);
build(1,1,n);
while(m--){
int t,l,r;
scanf("%d%d%d",&t,&l,&r);
if(t == 1)printf("%lld\n",ask(1,1,n,l,r));
if(t == 2){
int k;scanf("%d",&k);
change(1,1,n,l,r,k);
}
}
return 0;
}