[nowcoder]紅球進黑洞

題目

鏈接:https://ac.nowcoder.com/acm/contest/6046/C

時間限制:C/C++ 3秒,其他語言6秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述
在心理疏導室中有一種奇特的疏導工具,叫做紅球。紅球被提前分爲了許多正方形小方格。
每當有人來找ATB做心理疏導時,ATB就會讓他去先玩紅球,然後通過紅球小格方的高度來判斷一個人的壓力程度的高低
具體地講,ATB會讓該人對於一個序列執行以下操作

  1. 區間求和,即輸入l,r,輸出i=lrai\sum_{i=l}^{r}a_i
  2. 區間異或,即輸入l,r,k,對於lirl ≤ i ≤ r,將xix_i變爲xikx_i⊕k
    可是ATB天天算計那麼多答案,已經對這份工作產生了厭煩,所以請你幫幫他,對於一組給定的數據,輸出對應的答案
    ATB會將你感謝到爆

輸入描述:

第一行兩個整數n和m,表示數列長度和詢問次數
第二行有nn個整數,表示這個數列的初始數值
接下來有mm行,形如 1 l r 或者 2 l r k
分別表示查詢i=lrai\sum_{i=l}^{r}a_i
或者對於lirl ≤ i ≤ r,將xix_i變爲xikx_i⊕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

備註:

  1. 數據範圍
    對於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
  2. 說明
    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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章