这道题暴力枚举居然可以过

P2801 教主的魔法

BzhH @ 2021-01-31 15:59:06

暴力枚举的代码,分块后找到每个块中的最大值最小值,然后暴力枚举,理论上复杂度最坏可达O(nm),居然过了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define get(i) (i - 1) / len
using namespace std;
const int N = 1e6 + 5;

int hi[N], add[1005], len, Min[1005], Max[1005];

void update(int l, int r, int c)
{
    if (get(l) == get(r))
    {
        for (int i = l; i <= r; i++)
            hi[i] += c;
        int k = get(l);
        Min[k] = 0x3f3f3f3f, Max[k] = 0;
        for (int i = k * len + 1; i <= k * len + len; i++)
            Min[k] = min(Min[k], hi[i]), Max[k] = max(Max[k], hi[i]);
    }
    else 
    {
        int i = l, j = r;
        while (get(i) == get(l))
            hi[i] += c, i++;
        while (get(j) == get(r))
            hi[j] += c, j--;
        for (int k = get(i); k <= get(j); k++)
            add[k] += c, Min[k] += c, Max[k] += c;
        Min[get(l)] = 0x3f3f3f3f;
        for (int k = get(l) * len + 1; k < i; k++)
            Min[get(l)] = min(Min[get(l)], hi[k] + add[get(l)]), Max[get(l)] = max(Max[get(l)], hi[k] + add[get(l)]);
        for (int k = j + 1; k <= get(r) * len; k++)
            Min[get(r)] = min(Min[get(r)], hi[k] + add[get(r)]), Max[get(r)] = max(Max[get(r)], hi[k] + add[get(r)]);
    }
}

int query(int l, int r, int w)
{
    int res = 0;
    if (get(l) == get(r))
    {
        for (int i = l; i <= r; i++)
            res += (hi[i] + add[get(l)] >= w);
    }
    else 
    {
        int i = l, j = r;
        while (get(i) == get(l))
            res += (hi[i] + add[get(i)] >= w), i++;
        while (get(j) == get(r))
            res += (hi[j] + add[get(j)] >= w), j--;
        for (int k = get(i); k <= get(j); k++)
        {
            if (Min[k] >= w)
                res += len;
            else if (Min[k] <= w && Max[k] >= w)
            {

                for (int u = k * len + 1; u <= k * len + len; u++)
                    res += (hi[u] + add[k] >= w);
            }
        }
    }
    return res;
}

int main()
{
    int n, q;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        scanf("%d", &hi[i]);
    memset(Min, 0x3f, sizeof(Min));
    len = sqrt(n);
    for (int i = 0; i <= get(n); i++)
    {
        int l = i * len + 1, r = i * len + len;
        for (int j = l; j <= r; j++)
            Min[i] = min(hi[j], Min[i]), Max[i] = max(hi[j], Max[i]);
    }
    while (q--)
    {
        char op;
        int l, r, c;
        scanf(" %c%d%d%d", &op, &l, &r, &c);
        if (op == 'M')
            update(l, r, c);
        else
            printf("%d\n", query(l, r, c));
    }
    return 0;
}

by HMP_Haoge @ 2021-01-31 16:03:26

卧槽,那我之前交了一页的假分块????


by Link_Space @ 2021-01-31 17:22:46

戳鸡


|