鏈接: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
,輸出 - 區間異或,即輸入
l,r,k
,對於,將變爲
可是ATB天天算計那麼多答案,已經對這份工作產生了厭煩,所以請你幫幫他,對於一組給定的數據,輸出對應的答案
ATB會將你感謝到爆
輸入描述:
第一行兩個整數n和m,表示數列長度和詢問次數
第二行有個整數,表示這個數列的初始數值
接下來有行,形如 1 l r
或者 2 l r 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
備註:
- 數據範圍
對於30%30%30%的數據,保證 n, m, k≤ 10
對於另外30%30%30%的數據,保證 n, m ≤ 50000, k ∈ {0, 1}
對於全部100%100%100%的數據,保證 1 ≤ n,m ≤ 105, 0≤ ai,k ≤ 105 - 說明
a⊕b 表示 a xor b
題解:
將數字拆成20個線段樹
這樣就變成計算區間異或1,和求區間1的個數
碼力題
#include<bits/stdc++.h>
#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;
}