牛客小白月賽9 C 紅球進黑洞【線段樹+模擬位運算】
阿新 • • 發佈:2018-11-19
時間限制:C/C++ 3秒,其他語言6秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld
題目描述
在心理疏導室中有一種奇特的疏導工具,叫做紅球。紅球被提前分為了許多正方形小方格。
每當有人來找ATB做心理疏導時,ATB就會讓他去先玩紅球,然後通過紅球小格方的高度來判斷一個人的壓力程度的高低
具體地講,ATB會讓該人對於一個序列執行以下操作
1. 區間求和,即輸入l,r,輸出
2. 區間異或,即輸入l,r,k,對於l ≤ i ≤ r,將xi變為
可是ATB天天算計那麼多答案,已經對這份工作產生了厭煩,所以請你幫幫他,對於一組給定的資料,輸出對應的答案
ATB會將你感謝到爆
輸入描述:
第一行兩個整數n和m,表示數列長度和詢問次數
第二行有n個整數,表示這個數列的初始數值
接下來有m行,形如 1 l r 或者 2 l r k
分別表示查詢
或者對於l ≤ i ≤ r,將xi變為
輸出描述:
對於每一個查詢操作,輸出查詢的結果並換行
示例1
輸入
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. 資料範圍 對於的資料,保證 n, m, k≤ 10 對於另外的資料,保證 n, m ≤ 50000, k ∈ {0, 1}
對於全部的資料,保證 1 ≤ n,m ≤ 105, 0≤ ai,k ≤ 105
2. 說明
表示
思路:
主要問題是處理Xor操作。可以用一個二維的線段樹維護,第二維儲存每一位中1的個數。然後區間更新。如果k的當前位為1,那麼將tree[v][i]中的0變為1,1變為0,即1的個數為(R-L+1)-tree[v][i]。複雜度為O(nlogn*40)。
程式碼:
#include<bits/stdc++.h> using namespace std; #define MAXN 100005 #define ll long long int n,m; ll tree[4*MAXN][40],laz[4*MAXN],que; void build(int v,int L,int R) { if(L==R) { ll d; scanf("%lld",&d); for(int i=0;d;i++) { tree[v][i]=d&1; d>>=1; } } else { int mid=(L+R)/2; build(v*2,L,mid); build(v*2+1,mid+1,R); for(int i=0; i<40; i++) tree[v][i]=tree[v*2][i]+tree[v*2+1][i]; } } void pushdown(int L,int R,int v) { laz[v*2]^=laz[v]; laz[v*2+1]^=laz[v]; int d=laz[v]; int mid=(L+R)/2; for(int i=0; i<20 && d; i++,d>>=1) { if(d&1) { tree[v*2][i]=(mid-L+1)-tree[v*2][i]; tree[v*2+1][i]=(R-mid)-tree[v*2+1][i]; } } laz[v]=0; } void updata(int v,int L,int R,int ql,int qr,ll q) { if(ql<=L && R<=qr) { ll d=q; for(int i=0; i<20 && d; i++,d>>=1) { if(d&1) tree[v][i]=(R-L+1)-tree[v][i]; } laz[v]^=q; return; } if(laz[v]) pushdown(L,R,v); int mid=(L+R)/2; if(ql<=mid) updata(v*2,L,mid,ql,qr,q); if(qr>mid) updata(v*2+1,mid+1,R,ql,qr,q); for(int i=0; i<40; i++) tree[v][i]=tree[v*2][i]+tree[v*2+1][i]; } void query(int v,int L,int R,int ql,int qr) { if(ql<=L && R<=qr) { for(int i=0; i<40; i++) que+=(1LL<<i)*tree[v][i]; return; } if(laz[v]) pushdown(L,R,v); int mid=(L+R)/2; if(ql<=mid) query(v*2,L,mid,ql,qr); if(qr>mid) query(v*2+1,mid+1,R,ql,qr); } int main() { scanf("%d%d",&n,&m); memset(tree,0,sizeof tree); memset(laz,0,sizeof laz); build(1,1,n); for(int i=0; i<m; i++) { int op,l,r; ll d; scanf("%d",&op); if(op==2) { scanf("%d%d%lld",&l,&r,&d); updata(1,1,n,l,r,d); } else { scanf("%d%d",&l,&r); que=0; query(1,1,n,l,r); printf("%lld\n",que); } } return 0; }