📜  门|门CS 2008 |第 81 题(1)

📅  最后修改于: 2023-12-03 15:42:22.334000             🧑  作者: Mango

题目介绍:门门CS 2008 第81题

本题是一个模拟题,考察对数组和逻辑的掌握。

题目描述

一个长度为 $N$ 的序列,开始时所有元素都为 0。现在有 $M$ 次操作,每次操作将区间 $[L, R]$ 内的数全部加上 $C$。请你求出进行完所有操作后,整个序列中有多少元素大于等于 $T$。

输入格式

第一行输入三个数字 $N$, $M$, $T$。 接下来 $M$ 行,每行 $3$ 个数字 $L$, $R$, $C$。

输出格式

一个数字表示大于等于 $T$ 的元素个数。

输入样例1
5 3 3
1 3 2
2 4 1
3 5 3
输出样例1
2
解题思路

我们可以使用标记永久化 LazyTag 的方法来维护区间加操作。即对于每个节点,需要记录其区间加的懒标记,每次查询时,将懒标记向下传递,最终得到每个节点的值。

具体实现上,采用分治的思想,将原序列划分为若干个区间,然后对于每个区间记录其对应的节点。对于每个节点,我们需要记录其值和懒标记。值表示该区间内所有元素的和,懒标记表示该区间内所有元素需要加上的值。

在进行区间加操作时,我们需要将操作作用于查询区间的节点,并将懒标记标记为需要加上的值。在查询时,将懒标记传递到下层节点,然后根据查询的区间,将目标区间按中点进行划分,递归向下查询,并将查询结果做合并。

代码示例
#include <stdio.h>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 500010;

int n, m, T;
int w[N], son[N][2];
int idx;
struct Node
{
    int l, r;
    int sum, add;
} tr[N * 40];

int build(int l, int r)
{
    int u = ++idx;
    if (l == r) tr[u] = {l, r, w[l], 0};
    else
    {
        int mid = l + r >> 1;
        son[u][0] = build(l, mid), son[u][1] = build(mid + 1, r);
        tr[u] = {l, r, tr[son[u][0]].sum + tr[son[u][1]].sum, 0};
    }
    return u;
}

int modify(int u, int l, int r, int c)
{
    int p = ++idx;
    tr[p] = tr[u];
    tr[p].add += c;
    tr[p].sum += (min(r, tr[p].r) - max(l, tr[p].l) + 1) * c;

    if (tr[p].l >= l && tr[p].r <= r) return p;
    int mid = tr[p].l + tr[p].r >> 1;
    if (l <= mid) son[p][0] = modify(son[u][0], l, r, c);
    else son[p][0] = son[u][0];
    if (r > mid) son[p][1] = modify(son[u][1], l, r, c);
    else son[p][1] = son[u][1];

    tr[p].sum = tr[son[p][0]].sum + tr[son[p][1]].sum + (tr[p].r - tr[p].l + 1) * tr[p].add;
    return p;
}

int query(int u, int l, int r)
{
    if (l <= tr[u].l && r >= tr[u].r) return tr[u].sum;
    int mid = tr[u].l + tr[u].r >> 1;
    int sum = 0;
    if (l <= mid) sum += query(son[u][0], l, r);
    if (r > mid) sum += query(son[u][1], l, r);

    return sum + (min(r, tr[u].r) - max(l, tr[u].l) + 1) * tr[u].add;
}

int main()
{
    scanf("%d%d%d", &n, &m, &T);
    for (int i = 1; i <= n; i++) scanf("%d", &w[i]);

    build(1, n);

    while (m--)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        modify(1, l, r, c);
    }

    int ans = 0;
    for (int i = 1; i <= n; i++) ans += query(1, i, i) >= T;
    printf("%d\n", ans);

    return 0;
}

时间复杂度$O(m\log n)$。