树状数组1

详细内容可参考博客:
树状数组

P3374 【模板】树状数组 1

传送门

P3374 【模板】树状数组 1

Code

#include <iostream>
#include <cstdio>
using namespace std;

inline int yread()
{
	int x = 0, f = 1; char c = getchar();
	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
	return f * x; 
}

int n,m,c[500050];

inline void add(int x, int val)
{
	for (; x <= n; x += x & -x) c[x] += val;
}

inline int yask(int x)
{
	int ans = 0;
	for (; x; x -= x & -x) ans += c[x];
	return ans;
}

int main()
{
	n = yread(), m = yread();
	for (int i = 1; i <= n; ++i)
	{
		int x = yread();
		add(i, x);
	}
	for (int i = 1; i <= m; ++i)
	{
		int opt = yread(), x = yread(), y = yread();
		if (opt == 1) add(x, y);
		else printf("%d\n",yask(y) - yask(x - 1));
	}
	return 0;
}

P3368 【模板】树状数组 2 & 242. 一个简单的整数问题

传送门

P3368 【模板】树状数组 2
242. 一个简单的整数问题

算法分析

在这里插入图片描述

Code

//P3368 【模板】树状数组 2
#include <iostream>
#include <cstdio>
using namespace std;

inline int yread()
{
	int x = 0, f = 1; char c = getchar();
	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
	return f * x; 
}

const int maxn = 500050;
int n,m,a[maxn],c[maxn];

inline void add(int x, int val)
{
	for (; x <= n; x += x & -x) c[x] += val;
}

inline int yask(int x)
{
	int ans = 0;
	for (; x; x -= x & -x) ans += c[x];
	return ans;
}


int main()
{
	n = yread(), m = yread();
	for (int i = 1; i <= n; ++i)
		a[i] = yread();
	for (int i = 1; i <= m; ++i)
	{
		int opt = yread();
		if (opt == 1)
		{
			int x = yread(), y = yread(), k = yread();
			add(x, k); add(y + 1, -k);
		}
		else
		{
			int x = yread();
			printf("%d\n",a[x] + yask(x));
		}
	}
	return 0;
}
//242. 一个简单的整数问题
#include <iostream>
#include <cstdio>
using namespace std;

inline int yread()
{
	int x = 0, f = 1; char c = getchar();
	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
	return f * x; 
}

const int maxn = 100050;
int n,m,a[maxn],c[maxn];

inline void add(int x, int val)
{
	for (; x <= n; x += x & -x) c[x] += val;
}

inline int yask(int x)
{
	int ans = 0;
	for (; x; x -= x & -x) ans += c[x];
	return ans;
}


int main()
{
	n = yread(), m = yread();
	for (int i = 1; i <= n; ++i)
		a[i] = yread();
	for (int i = 1; i <= m; ++i)
	{
		char opt; scanf("%c",&opt);
		if (opt == 'C')
		{
			int x = yread(), y = yread(), k = yread();
			add(x, k); add(y + 1, -k);
		}
		else
		{
			int x = yread();
			printf("%d\n",a[x] + yask(x));
		}
	}
	return 0;
}

243. 一个简单的整数问题2

传送门

243. 一个简单的整数问题2

算法分析

在这里插入图片描述在这里插入图片描述温馨提示:
本题数据有误
有一组数据的指令后面有一个空格,会把scanf和getchar()卡掉

Code

//树状数组
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;

inline ll yread()
{
	ll x = 0, f = 1; char c = getchar();
	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
	return f * x; 
}

const int maxn = 100050;
int n,m,a[maxn];
ll c[2][maxn],sum[maxn];

inline void add(int k, int x, int val)
{
	for (; x <= n; x += x & -x) c[k][x] += val;
}

inline ll yask(int k, int x)
{
	ll ans = 0;
	for (; x; x -= x & -x) ans += c[k][x];
	return ans;
}

int main()
{
	n = yread(), m = yread();
	for (int i = 1; i <= n; ++i)
	{
		a[i] = yread();
		sum[i] = sum[i-1] + a[i];
	}
	for (int i = 1; i <= m; ++i)
	{
		char opt; cin >> opt;
		if (opt == 'C')
		{
			int l = yread(), r = yread(), d = yread();
			add(0, l, d); add(0, r + 1, -d);
			add(1, l, d * l); add(1, r + 1, -d * (r + 1));
		}
		else
		{
			int l = yread(), r = yread();
			ll ans = (sum[r]+(r+1)*yask(0,r)-yask(1,r))-(sum[l-1]+l*yask(0,l-1)-yask(1,l-1));
			printf("%lld\n",ans);
		}
	}
	return 0;
}
//这之前用分块写的,可见树状数组的代码量很小
#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;

inline ll read()
{
	ll x = 0, f = 1; char c = getchar();
	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
	return f * x; 
}

const int maxn = 100050;
ll n,m,a[maxn],l,r,d,ans;
ll bk,bl[maxn],lazy[maxn],L[maxn],R[maxn],sum[maxn];

inline void add(ll l, ll r, ll d)
{
	int p = bl[l], q = bl[r];
    if (p == q)
	{
        for (int i = l; i <= r; i++) a[i] += d;
        sum[p] += d * (r - l + 1);
    } else 
	{
	    for (int i = p + 1; i <= q - 1; i++) lazy[i] += d;
	    for (int i = l; i <= R[p]; i++) a[i] += d;
	    sum[p] += (R[p] - l+1) * d;
	    for (int i = L[q]; i <= r; i++) a[i] += d;
	    sum[q] += (r - L[q] + 1) * d;
    }
}

inline ll ask(ll l, ll r)
{
	ll p = bl[l], q = bl[r];
	ll ans = 0;
	if (p == q)
	{
		for (int i = l; i <= r; ++i)
			ans += a[i];
		ans += lazy[p] * (r - l + 1);
	}else
	{
		for (int i = p + 1; i <= q - 1; i++)
            ans += sum[i] + lazy[i] * (R[i] - L[i] + 1);
        for (int i = l; i <= R[p]; i++) ans += a[i];
        ans += (R[p] - l + 1) * lazy[p];
        for (int i = L[q]; i <= r; i++) ans += a[i];
        ans += (r - L[q] + 1) * lazy[q];
	}
	return ans;
}

int main()
{
	n = read(), m = read();
	bk = sqrt(n);
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 1; i <= bk; i++)
	{
        L[i] = (i - 1) * bk + 1;
        R[i] = i * bk;
    }
    if (R[bk] < n) bk++, L[bk] = R[bk - 1] + 1, R[bk] = n;
    for (int i = 1; i <= bk; i++)
        for (int j = L[i]; j <= R[i]; j++)
            bl[j] = i, sum[i] += a[j];
	char c;
	for (int i = 1; i <= m; ++i)
	{
		cin >> c;
		if (c == 'C')
		{
			l = read(), r = read(), d = read();
			add (l, r, d);
		}
		else if (c == 'Q')
		{
			l = read(), r = read();
			printf("%lld\n",ask(l, r));
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组(Fenwick Tree)是一种用于快速维护数组前缀和的数据结构。它可以在 $O(\log n)$ 的时间内完成单点修改和前缀查询操作,比线段树更加简洁高效。 下面是 Java 实现的树状数组详解: 首先,在 Java 中我们需要使用数组来表示树状数组,如下: ``` int[] tree; ``` 接着,我们需要实现两个基本操作:单点修改和前缀查询。 单点修改的实现如下: ``` void update(int index, int value) { while (index < tree.length) { tree[index] += value; index += index & -index; } } ``` 该函数的参数 `index` 表示要修改的位置,`value` 表示修改的值。在函数内部,我们使用了一个 `while` 循环不断向上更新树状数组中相应的节点,直到到达根节点为止。具体来说,我们首先将 `tree[index]` 加上 `value`,然后将 `index` 加上其最后一位为 1 的二进制数,这样就可以更新其父节点了。例如,当 `index` 为 6 时,其二进制表示为 110,最后一位为 2^1,加上后变为 111,即 7,这样就可以更新节点 7 了。 前缀查询的实现如下: ``` int query(int index) { int sum = 0; while (index > 0) { sum += tree[index]; index -= index & -index; } return sum; } ``` 该函数的参数 `index` 表示要查询的前缀的结束位置,即查询 $[1, index]$ 的和。在函数内部,我们同样使用了一个 `while` 循环不断向前查询树状数组中相应的节点,直到到达 0 为止。具体来说,我们首先将 `sum` 加上 `tree[index]`,然后将 `index` 减去其最后一位为 1 的二进制数,这样就可以查询其前一个节点了。例如,当 `index` 为 6 时,其二进制表示为 110,最后一位为 2^1,减去后变为 100,即 4,这样就可以查询节点 4 的值了。 最后,我们还需要初始化树状数组,将其全部置为 0。初始化的实现如下: ``` void init(int[] nums) { tree = new int[nums.length + 1]; for (int i = 1; i <= nums.length; i++) { update(i, nums[i - 1]); } } ``` 该函数的参数 `nums` 表示初始数组的值。在函数内部,我们首先创建一个长度为 `nums.length + 1` 的数组 `tree`,然后逐个将 `nums` 中的元素插入到树状数组中。具体来说,我们调用 `update(i, nums[i - 1])` 来将 `nums[i - 1]` 插入到树状数组的第 `i` 个位置。 到此为止,我们就完成了树状数组的实现。可以看到,树状数组的代码比线段树要简洁很多,而且效率也更高。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值