洛谷P2357 守墓人(差分+树状数组)

原题链接

什么是差分?
7 8 6 5 8 18 20 35 //原数组
7 1 -2 -1 3 10 2 15 //差分数组

差分数组的前缀sum[i]即原数组的a[i]

我们构建两个树状数组
sum1:7 1 -2 -1 3 10 2 15
sum2:7 2 -6 -4 15 60 14 120
第二个数组是sum1[i]*i
那么我们怎么算原数组的前缀和呢??

例如求前4个数的和7+8+6+5=26

=5*(7+1-2-1)-(7+2-6-4)=26

即有公式(求原数组前缀和)
sum(i)=(i+1)(sum1[1]+sum1[2]+…+sum1[i])-(sum2[1]+sum2[2]+…+sum2[i])
即(i+1)*差分数组前缀和(i)-差分数组乘坐标数组(即sum2)的前缀和

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <math.h>
#include <cstring>
#include <string.h>
#include <queue>
#include<list>
#include<cstdarg>
#define ll long long
using namespace std;
ll c[200010];
ll a[200010]; ll n, m, k;
inline ll lowbit(ll x) { return x & (-x); }

void add(ll x, ll d)
{
	for (ll i = x; i <= n; i += lowbit(i))
	{
		c[i] += d;
		a[i] += x * d;
	}
}

ll sum(ll x)
{
	ll s = 0;
	for (ll i = x; i; i -= lowbit(i))
	{
		s += (x + 1) * c[i] - a[i];
	}
	return s;
}
int main()
{
	cin >> n >> m;
	ll x;
	ll last = 0;
	for (ll i = 1; i <= n; i++)
	{
		cin >> x;
		add(i, x - last);
		last = x;
	}
	ll main_ = 0;
	while (m--)
	{
		ll op;
		cin >> op;
		if (op == 1)
		{
			ll t1, t2, t3;
			cin >> t1 >> t2 >> t3;
			add(t1, t3);
			add(t2 + 1, -t3);
		}
		if (op == 2)
		{
			ll t3;
			cin >> t3;
			main_ += t3;
		}
		if (op == 3)
		{
			ll t3;
			cin >> t3;
			main_ -= t3;
		}
		if (op == 4)
		{
			ll t1, t2;
			cin >> t1 >> t2;
			if (t1 == 1)
			{
				cout << sum(t2) - sum(t1 - 1) + main_ << '\n';
			}
			else cout << sum(t2) - sum(t1 - 1) << '\n';
		}
		if (op == 5)
		{
			cout << sum(1) + main_ << '\n';
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shihao Weng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值