zoukankan      html  css  js  c++  java
  • 牛客小白月赛9-红球进黑洞(异或线段树)

    题意:

    操作 (1):求 ([l,r]) 区间和。
    操作 (2):区间 ([l,r]) 的数异或上(k)

    分析:

    对区间进行位运算是没啥公式的,所以要考虑对数的每一位建线段树,记录每一位 (1) 出现的次数。询问的时候求出每一位的贡献即可。
    线段树维护的是每一位 (1) 的出现次数。
    区间异或:首先如果 (k)(i) 位为 (0),则异或值不变,否则异或 (i) 位的区间 ([l,r]) 相当于将这个区间的 (0) 变成 (1)(1)变成 (0)
    区间或:或上某一位1才有意义
    区间与:与上某一位0才有意义

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int N = 1e5 + 5;
    const int mod = 1e9 + 7;
    
    int n, q, w[N];
    int seg[N << 2][19], lazy[N << 2][19];
    int opt, res, x, y, k;
    LL ans, base;
    
    void build(int rt, int l, int r, int o) {
    	if (l == r) {
    		seg[rt][o] += ((w[l] >> o) & 1);
    		return ;
    	}
    	int mid = l + r >> 1;
    	build(rt << 1, l, mid, o);
    	build(rt << 1 | 1, mid + 1, r, o);
    	seg[rt][o] = seg[rt << 1][o] + seg[rt << 1 | 1][o];
    }
    
    void pushdown(int rt, int l, int r, int mid, int o) {
    	if (lazy[rt][o]) {
    		lazy[rt << 1][o] ^= 1;
    		lazy[rt << 1 | 1][o] ^= 1;
    		seg[rt << 1][o] = (mid - l + 1) - seg[rt << 1][o];
    		seg[rt << 1 | 1][o] = (r - mid) - seg[rt << 1 | 1][o];
    		lazy[rt][o] ^= 1;
    	}
    }
    
    void update(int rt, int l, int r, int ql, int qr, int o) {
    	if (l >= ql && r <= qr) {
    		seg[rt][o] = (r - l + 1) - seg[rt][o];
    		lazy[rt][o] ^= 1;
    		return ; 
    	}
    	int mid = l + r >> 1;
    	pushdown(rt, l, r, mid, o);
    	if (ql <= mid) update(rt << 1, l, mid, ql, qr, o);
    	if (qr > mid) update(rt << 1 | 1, mid + 1, r, ql, qr, o);
    	seg[rt][o] = seg[rt << 1][o] + seg[rt << 1 | 1][o];
    }
    
    int query(int rt, int l, int r, int ql, int qr, int o) {
    	if (l >= ql && r <= qr) {
    		return seg[rt][o];
    	}
    	int mid = l + r >> 1, ans = 0;
    	pushdown(rt, l, r, mid, o);
    	if (ql <= mid) ans += query(rt << 1, l, mid, ql, qr, o);
    	if (qr > mid) ans += query(rt << 1 | 1, mid + 1, r, ql, qr, o);
    	return ans;
    }
    
    int main() {
    	scanf("%d %d", &n, &q);
    	for (int i = 1; i <= n; i++) scanf("%d", w + i);
    	for (int i = 0; i <= 17; i++) build(1, 1, n, i);
    	while (q--) {
    		scanf("%d", &opt);
    		if (opt == 1) {
    			scanf("%d %d", &x, &y);
    			ans = 0, base = 1;
    			for (int i = 0; i <= 17; i++) {
    				ans += 1LL * base * query(1, 1, n, x, y, i);
    				base <<= 1;
    			}
    			printf("%lld
    ", ans);
    		} else {
    			scanf("%d %d %d", &x, &y, &k);
    			for (int i = 0; i <= 17; i++) {
    				res = ((k >> i) & 1);
    				if (res) update(1, 1, n, x, y, i);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    BZOJ 3205 [Apio2013]机器人 ——斯坦纳树
    BZOJ 3782 上学路线 ——动态规划 Lucas定理 中国剩余定理
    HDU 1423 Greatest Common Increasing Subsequence ——动态规划
    BZOJ 3309 DZY Loves Math ——莫比乌斯反演
    POJ 1038 Bugs Integrated, Inc. ——状压DP
    POJ 3693 Maximum repetition substring ——后缀数组
    POJ 2699 The Maximum Number of Strong Kings ——网络流
    POJ 2396 Budget ——有上下界的网络流
    BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
    源码安装python
  • 原文地址:https://www.cnblogs.com/ChaseNo1/p/11657287.html
Copyright © 2011-2022 走看看