【线段树】区间异或,正常求和

题目

给定 n 个数的序列 a。m 次操作,操作有两种:
1.求 ∑ i = l r a i \displaystyle\sum_{i=l}^r a_i i=lrai
2.把 a l ∼ a r a_l\sim a_r alar异或上x
const int MAXN = 100005, MAXW = 25;
int n, v[MAXW][MAXN];
struct Segment_tree {
	int n, val[MAXN << 2], tag[MAXN << 2];
	void Clear() {mst(val, 0); mst(tag, 0); n = 0;}
	#define ls (k << 1)
	#define rs (k << 1 | 1)
	#define mid ((l + r) >> 1)
	void Build(int num, int k, int l, int r) {
		if(l == r) {val[k] = v[num][l], tag[k] = 0; return;}
		Build(num, ls, l, mid); Build(num, rs, mid+1, r);
		val[k] = val[ls] + val[rs];
	}
	void pushdown(int k, int l, int r) {
		if(tag[k]) {
			tag[k] = 0, tag[ls] ^= 1, tag[rs] ^= 1;
			val[ls] = (mid-l+1) - val[ls];
			val[rs] = (r - mid) - val[rs];
//			assert(val[ls] >= 0); assert(val[rs] >= 0);
		}
	} 
	int query(int k, int l, int r, int ql, int qr) {
//		cout << l << ' ' << r << ' ' << ql << ' ' << qr << endl;
		if(l == ql && r == qr) return val[k];
		pushdown(k, l, r); assert(l <= r);
		if(qr <= mid) return query(ls, l, mid, ql, qr);
		else if(mid < ql) return query(rs, mid+1, r, ql, qr);
		else return query(ls, l, mid, ql, mid) + query(rs, mid+1, r, mid+1, qr);
	}
	int Query(int l, int r) {return query(1, 1, n, l, r);}
	void rev(int k, int l, int r, int rl, int rr) {
		if(l == rl && r == rr) {
			tag[k] ^= 1; val[k] = (r - l + 1) - val[k];
			return;
		}
		pushdown(k, l, r);
		if(rr <= mid) rev(ls, l, mid, rl, rr);
		else if(mid < rl) rev(rs, mid+1, r, rl, rr);
		else {rev(ls, l, mid, rl, mid); rev(rs, mid+1, r, mid+1, rr);}
		val[k] = val[ls] + val[rs];
	}
	void Reverse(int l, int r) {rev(1, 1, n, l, r);}
}tr[MAXW];
signed main()
{
	cin >> n;
	For(i, 1, n) {
		int x = read();
		for(int j = 0; (1 << j) <= x; j++)
			v[j][i] = (x >> j) & 1;
	}
	For(i, 0, 20) {
		tr[i].Clear(); tr[i].n = n; 
		tr[i].Build(i, 1, 1, n);
	}
	int Qnum = read();
	while(Qnum--) {
		int op = read(), l = read(), r = read();
		if(op == 1) {
			int ans = 0;
			For(i, 0, 20)
				ans += tr[i].Query(l, r) * (1ll << i);
			printf("%lld\n", ans);
		} else {
			int x = read();
			For(i, 0, 20)
				if((x >> i) & 1)
					tr[i].Reverse(l, r);
		}
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值