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;
    }
    
  • 相关阅读:
    每天一个linux命令(54):sftp命令
    每天一个linux命令(53):wget命令
    每天一个linux命令(52):scp命令
    每天一个linux命令(51):rcp命令
    每天一个linux命令(50):telnet命令
    每天一个linux命令(49):ss命令
    每天一个linux命令(48):netstat命令
    每天一个linux命令(46):ping命令
    Springmvc常见问题
    MP实战系列(十)之SpringMVC集成SpringFox+Swagger2
  • 原文地址:https://www.cnblogs.com/ChaseNo1/p/11657287.html
Copyright © 2011-2022 走看看