(線段樹)小白月賽9-C紅球進白洞
阿新 • • 發佈:2018-11-28
https://ac.nowcoder.com/acm/contest/275/C
具體地講,ATB會讓該人對於一個序列執行以下操作
- 區間求和,即輸入l, r,輸出xi(l <= i <= r)的和
- 區間異或,即輸入l,r,k,對於l ≤ i ≤ r,將xi變為xi ^ k
可是ATB天天算計那麼多答案,已經對這份工作產生了厭煩,所以請你幫幫他,對於一組給定的資料,輸出對應的答案
線段樹考慮異或操作的特性,以二進位制來分析,如果該位置上為0,並不會影響xi的值,如果該位置為1,會將原來的0變為1,原來的1變為0,即為總1-原1
#include<bits/stdc++.h> using namespace std; #define mid ((l + r) >> 1) #define lc (rt << 1) #define rc (rt << 1 | 1) typedef long long ll; const int maxn = 1e5 + 10; int sum[maxn << 2][21], lazy[maxn << 2]; void push_up(int rt) { for(int i = 0; i < 20; i++) sum[rt][i] = sum[lc][i] + sum[rc][i]; } void build(int rt, int l, int r) { if(l == r) { int x; scanf("%d", &x); for(int i = 0; i < 20; i++) { if(x & (1 << i)) sum[rt][i] = 1; else sum[rt][i] = 0; } return; } build(lc, l, mid); build(rc, mid + 1, r); push_up(rt); } void push_down(int l, int r, int rt) { if(lazy[rt] == 0) return; lazy[lc] ^= lazy[rt]; lazy[rc] ^= lazy[rt]; int len = r - l + 1; for(int i = 0; i < 20; i++) { if(lazy[rt] & (1 << i)) { sum[lc][i] = (l + r) / 2 - l + 1 - sum[lc][i]; sum[rc][i] = r - (l + r) / 2 - sum[rc][i]; } } lazy[rt] = 0; } ll query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) { ll ans = 0; for(int i = 0; i < 20; i++) ans += ((ll)sum[rt][i] << i); return ans; } push_down(l, r, rt); if(L > mid) return query(L, R, mid + 1, r, rc); else if(R <= mid) return query(L, R, l, mid, lc); return query(L, mid, l, mid, lc) + query(mid + 1, R, mid + 1, r, rc); } void update(int L, int R, int k, int l, int r, int rt) { if(L <= l && r <= R) { lazy[rt] ^= k; for(int i = 0; i < 20; i++) if(k & (1 << i)) sum[rt][i] = r - l + 1 - sum[rt][i]; //異或特性,如果異或值該位置為1,按分析區間總1-原1 return; } push_down(l, r, rt); if(L > mid) update(L, R, k, mid + 1, r, rc); else if(R <= mid) update(L, R, k, l, mid, lc); else { update(L, mid, k, l, mid, lc); update(mid + 1, R, k, mid + 1, r, rc); } push_up(rt); } int main() { int n, m, t, l, r, k; scanf("%d%d", &n, &m); register int i; build(1, 1, n); while(m--) { scanf("%d%d%d", &t, &l, &r); if(t == 1) printf("%lld\n", query(l, r, 1, n, 1)); else if(t == 2) { scanf("%d", &k); update(l, r, k, 1, n, 1); } } }