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

这篇博客介绍了如何利用线段树和lowbit(二进制最高位的1)性质解决区间加权和区间查询的问题。通过建立线段树并维护懒标记,实现了高效的操作。代码示例展示了如何实现快速计算lowbit,以及如何在线段树中进行区间更新和查询,确保在O(logN)的时间复杂度内完成任务。
摘要由CSDN通过智能技术生成

请添加图片描述
大意:两种操作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();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值