树状数组练习题codeforces.com/problemset/…
不难看出,整道题对于区间和的查询是一个难点,如何巧妙地查询每天能够完成的订单数呢?
不妨考虑对于每一次操作2,它将整个长度为 的序列分成了三个部分,一个是 ,一个是 ,一个是 ,其中对于第一个区间,它每天的生产力为 ,第二个区间的生产力为 ,第三个区间的生产力为 。
可以看出我们只需要对第一个和第三个区间求和就可以了,那么怎么求和呢?我们考虑维护两个树状数组,记第 天的订单数为 ,则一个用来维护 ,一个用来维护 ,则在查询时直接分别查询对应的区间即可。
那么我们又应该怎么进行单点更新呢?设当前第 天新增 个订单,以维护 的树状数组为例,则若 ,则直接更新,否则令 ,将这天的订单数直接修改为 。如此单点更新和区间查询就都解决了。
coding:
#include <iostream>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(x) cout << #x << "=" << x << "\n";
ll n, k, a, b, q;
class fenwick_tree
{
private:
int n;
vector<ll> bit;
public:
fenwick_tree(const int n)
{
this->n = n;
bit.resize(n + 1, 0);
}
int lowbit(int x)
{
return x & (-x);
}
void update(int idx, ll val)
{
while (idx <= n)
{
bit[idx] += val;
idx += lowbit(idx);
}
}
ll query(int idx)
{
ll sum = 0;
while (idx)
{
sum += bit[idx];
idx -= lowbit(idx);
}
return sum;
}
ll query_range(int l, int r)
{
return query(r) - query(l - 1);
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> k >> a >> b >> q;
fenwick_tree fta(n), ftb(n);
int op;
while (q--)
{
cin >> op;
if (op == 1)
{
int d;
ll val;
cin >> d >> val;
ll val1 = fta.query_range(d, d);
ll val2 = ftb.query_range(d, d);
if (val1 + val <= a)
fta.update(d, val);
else
fta.update(d, a - val1);
if (val2 + val <= b)
ftb.update(d, val);
else
ftb.update(d, b - val2);
}
else
{
int p;
cin >> p;
ll sum1 = 0, sum2 = 0;
if (p > 1)
sum1 = ftb.query_range(1, p - 1);
if (p + k <= n)
sum2 = fta.query_range(p + k, n);
cout << sum1 + sum2 << "\n";
}
}
return 0;
}