题意:
一个工厂需要生产一些木材,每天可以生产a个,但是因为一些机器坏了,所以一天只能生产b个,可以选择某一天开始修复机器,修好需要k天,并且这段时间不能再生产,之后会恢复到产量a。在n天中,工厂会接一些订单,每个订单需要一个木材并且在当天生产完成。然后给出q个操作,有两种格式:
\(1, d_i, a_i\) 表示在第di天新增了\(a_i\)个订单;
\(2, p_i\) 表示选择在第pi天修复机器。
输出对每个\(p_i\),最多可以满足总共多少订单。注意:修复只能修一次,相当于一次独立的查询
思路:
可以利用树状数组来维护修复前后的订单量,每增加\(a_i\)订单,就对\(d_i\)执行更新操作,因为修复前后每天的生产量不同,修复前最大为a,修复后最大为b,所以要维护两个不同的订单量,并且每次增加订单后,当天的生产量不能超过最大的生产量,所以更新时不能一直增加,用\(order[d_i]\)记录当天累积的订单量,用新增后当天的订单量和最大生产量的较小值,减去增加前的订单量和最大生产量的较小值来更新,即可保证维护的每天的订单量不会超过最大的生产量。最后输出\([1, p_i - 1]\)和\([p_i + k, n]\)这两个最大产量不同的区间和的和即可(注意利用树状数组求区间和时的端点)。
#include <iostream>
#include <algorithm>
using namespace std;
#define FIO ios_base::sync_with_stdio(false); cin.tie(nullptr);
const int INF = 0x3f3f3f3f;
const int MAXN = 200010;
int tree[2][MAXN];
int lowbit(int x)
{
return x & (-x);
}
void update(int x, int add, int type)
{
while (x <= MAXN)
{
tree[type][x] += add;
x += lowbit(x);
}
}
int sum(int x, int type)
{
int s = 0;
while (x)
{
s += tree[type][x];
x -= lowbit(x);
}
return s;
}
int order[MAXN];
int main()
{
int n, k, a, b, q;
cin >> n >> k >> a >> b >> q;
for (int i = 0; i < q; ++i)
{
int op;
cin >> op;
if (op == 1)
{
int day, num;
cin >> day >> num;
int previous = order[day];
order[day] += num;
update(day, min(b, order[day]) - min(b, previous), 0);
update(day, min(a, order[day]) - min(a, previous), 1);
}
else
{
int p;
cin >> p;
cout << sum(p - 1, 0) + (sum(n, 1) - sum(p + k - 1, 1)) << endl;
}
}
return 0;
}