CF 627B

29 阅读2分钟

树状数组练习题codeforces.com/problemset/…

不难看出,整道题对于区间和的查询是一个难点,如何巧妙地查询每天能够完成的订单数呢?

不妨考虑对于每一次操作2,它将整个长度为 nn 的序列分成了三个部分,一个是 [1,pi1][1,p_i-1] ,一个是 [pi,pi+k1][p_i,p_i+k-1] ,一个是 [pi+k,n][p_i+k,n] ,其中对于第一个区间,它每天的生产力为 bb ,第二个区间的生产力为 00 ,第三个区间的生产力为 aa

可以看出我们只需要对第一个和第三个区间求和就可以了,那么怎么求和呢?我们考虑维护两个树状数组,记第 ii 天的订单数为 tit_i ,则一个用来维护 min(a,ti)min(a,t_i) ,一个用来维护 min(b,ti)min(b,t_i) ,则在查询时直接分别查询对应的区间即可。

那么我们又应该怎么进行单点更新呢?设当前第 ii 天新增 valival_i 个订单,以维护 min(a,ti)min(a,t_i) 的树状数组为例,则若 ti+valiat_i+val_i≤a ,则直接更新,否则令 vali=atival_i=a-t_i ,将这天的订单数直接修改为 aa 。如此单点更新和区间查询就都解决了。

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;
}