hdu7116 lowbit (线段树+lowbit的性质)

请添加图片描述
大意:两种操作1给区间内所有ai加上lowbit(ai)
操作2:区间问询总和
lowbit的性质:lowbit(ai)会取ai二进制下的最高位的1,例如5的二进制是101,lowbit(5)=1,4的二进制是100,lowbit(4)=4;
用以下代码可以快速算出lowbit

int lowbit(int x) {
    
    
	return x & (-x);
}

另一个性质:一个数最多进行加log次lowbit,二进制就会变成1000……000的形式,此时再加lowbit就是这个数乘2.
用线段树+懒标记维护区间,加上一个标记来标明这个区间是需要lowbit还是直接*2

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10, mod = 998244353;
int n, m;
int w[N];

struct node {
    
    
	int num, l, r, ok, lazy;
} tr[4 * N];

int lowbit(int x) {
    
    
	return x & (-x);
}

void pushup(int u) {
    
    
	tr[u].num = (tr[u << 1].num + tr[u << 1 | 1].num) % mod;
	if (tr[u << 1].ok && tr[u << 1 | 1].ok)
		tr[u].ok = 1;
}

void pushdown(int u) {
    
    
	if (tr[u].lazy <= 1)
		return;
	tr[u << 1].num = tr[u << 1].num * tr[u].lazy % mod;
	tr[u << 1 | 1].num = tr[u << 1 | 1].num * tr[u].lazy % mod;
	tr[u << 1].lazy = tr[u << 1].lazy * tr[u].lazy % mod;
	tr[u << 1 | 1].lazy = tr[u << 1 | 1].lazy * tr[u].lazy % mod;
	tr[u].lazy = 1;
}

void build(int u, int l, int r) {
    
    
	tr[u] = {
    
    w[l], l, r, 0, 1};
	if (l == r) {
    
    
		if (tr[u].num == lowbit(tr[u].num))
			tr[u].ok = 1;
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
	pushup(u);
	return;
}

int query(int u, int l, int r) {
    
    
	//cout << u << " " << l << " " << r << endl;
	if (tr[u].l >= l && tr[u].r <= r) {
    
    
		return tr[u].num % mod;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	int res = 0;
	if (l <= mid)
		res += query(u << 1, l, r) % mod;
	if (r > mid)
		res = (res + query(u << 1 | 1, l, r)) % mod;
	return res;
}

void modify(int u, int l, int r) {
    
    
	//cout << u << " " << l << " " << r << endl;
	if (tr[u].l >= l && tr[u].r <= r && tr[u].ok) {
    
    
		tr[u].num = (tr[u].num * 2) % mod;
		tr[u].lazy = (tr[u].lazy * 2) % mod;
		return;
	}
	if (tr[u].l == tr[u].r && tr[u].l >= l && tr[u].r <= r) {
    
    
		tr[u].num += lowbit(tr[u].num);
		if (tr[u].num == lowbit(tr[u].num)) {
    
    
			tr[u].ok = 1;
			tr[u].num %= mod;
		}
		return;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if (mid >= l) {
    
    
		modify(u << 1, l, r);
	}
	if (mid < r) {
    
    
		modify(u << 1 | 1, l, r);
	}
	pushup(u);

}

void prin() {
    
    
	for (int i = 1; i <= n; i++) {
    
    
		cout << query(1, i, i) << " ";
	}
	cout << endl;
}

void solve() {
    
    
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> w[i];
	build(1, 1, n);
	cin >> m;
	while (m--) {
    
    
		int a, b, c;
		cin >> a >> b >> c;
		//prin();
		if (a == 1) {
    
    
			modify(1, b, c);
		} else {
    
    
			cout << query(1, b, c) << endl;
		}
	}
}


signed main() {
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
    
    
		solve();
	}
}

おすすめ

転載: blog.csdn.net/fdxgcw/article/details/120111558