QOJ.ac

QOJ

Time Limit: 6 s Memory Limit: 512 MB Total points: 100

#9638. 线段树与区间加

統計

题目描述

普罗在图书馆找到了一本关于算法的书。书中介绍了一种名为“线段树”的数据结构。

  • 线段树是一种有根的二叉树,其每个节点对应了序列上的一个区间 $[l, r]$,其中根节点对应 $[1, n]$。
  • 对于每个节点,若其代表的序列区间 $[l, r]$ 满足 $l = r$,则其为叶节点;否则存在整数 $k$($l \le k < r$),满足其左儿子代表区间 $[l, k]$,右儿子代表区间 $[k + 1, r]$。为了保证其时间复杂度,$k$ 一般会取 $\lfloor (l + r) / 2 \rfloor$。
  • 线段树可以实现单点修改,区间修改,区间查询等操作。其中区间修改操作的实现通常需要维护名为懒惰标记的额外信息。

在简单了解了线段树如何维护区间加之后,普罗想要实现一个维护区间加的线段树。于是他写下了如下的代码:

#define len(i) (r[i]-l[i]+1)
void push_down(unsigned i)
{
    a[lc[i]] += len(lc[i]) * lz[i];
    lz[lc[i]] += lz[i];
    a[rc[i]] += len(rc[i]) * lz[i];
    lz[rc[i]] += lz[i];
    lz[i] = 0;
    return;
}
void add(unsigned i, unsigned ql, unsigned qr, unsigned k)
{
    if (qr < l[i] || r[i] < ql) return;
    if (ql <= l[i] && r[i] <= qr) {
        a[i] += len(i) * k;
        lz[i] += k;
        return;
    }
    push_down(i);
    add(lc[i], ql, qr, k);
    add(rc[i], ql, qr, k);
    a[i] = a[lc[i]] + a[rc[i]];
    return;
}

(省略了其他部分,代码中所有变量均为 unsigned 类型)

为了检验这份代码的正确性,普罗构建了一个维护的序列长为 $n$ 的线段树,并在每个节点上设置两个额外的权值 $va_i, vb_i$。接下来他在线段树上进行了 $m$ 次区间加的操作,在每次区间加操作后输出了下面函数的返回值。

unsigned foobar() {
    unsigned tot = 0;
    for (unsigned i = 1; i < 2 * n; i++) tot += va[i] * a[i] + vb[i] * lz[i];
    return tot;
}

因为 K 博士的电脑实在太快了,普罗的代码只花了 1ms 就得出了结果。但是他还是不知道代码是不是正确的,所以请你计算出上面函数的结果和普罗得出的结果比较吧。

输入格式

第一行两个整数 $n, m$,表示线段树维护的序列长度和操作次数。

接下来 $2n - 1$ 行,第 $i$ 行首先是四个整数 $l_i, r_i, va_i, vb_i$,表示线段树上第 $i$ 个节点对应的区间的左端点和右端点,以及节点上的两个额外权值。如果这个节点不是根节点,那么接下来还有两个整数 $lc_i, rc_i$,表示这个节点的左儿子编号和右儿子编号。

接下来 $m$ 行,每行三个整数 $ql, qr, k$,表示一次区间加操作的左端点,右端点和增加的值。

输出格式

在每次区间加操作后输出一行一个正整数表示 foobar 函数的返回值。

样例输入 1

4 4
1 4 0 1 2 3
1 2 3 5 4 5
3 4 2 2 6 7
1 1 1 4
2 2 3 2
3 3 2 0
4 4 5 3
1 3 3
2 4 1
1 4 2
2 3 1

样例输出 1

45
74
76
154

样例输入 2

4 4
1 4 2 4 2 3
1 3 1 3 4 5
4 4 5 4
1 1 3 3
2 3 2 1 6 7
2 2 0 3
3 3 2 5
1 3 3
2 4 1
1 4 2
2 3 1

样例输出 2

36
82
106
155

样例输入 3

见附加文件中的 ex_data3.in

样例输出 3

见附加文件中的 ex_data3.ans

样例输入 4

见附加文件中的 ex_data4.in.

样例输出 4

见附加文件中的 ex_data4.ans.

样例输入 5

见附加文件中的 ex_data5.in.

样例输出 5

见附加文件中的 ex_data5.ans.

数据范围

测试点编号 $n, q$ 其他约定
$1 \sim 5$ $\le 2000$
$6 \sim 10$ $\le 40000$
$11 \sim 15$ $\le 2 \times 10^5$ 保证存在一个线段树上的节点对应的区间为 $[ql, qr]$
$16 \sim 20$ $\le 2 \times 10^5$ 保证不同的 $ql, qr$ 不超过 $200$ 种
$21 \sim 25$ $\le 2 \times 10^5$

如果测试点编号 $\text{mod} , 5$ 为 $2$ 或 $3$,该测试点保证 $va_i = 0$。

如果测试点编号 $\text{mod} , 5$ 为 $4$ 或 $0$,该测试点保证 $vb_i = 0$。

对于 $100\%$ 的数据,保证 $1 \le n, q \le 2 \times 10^5$,给出的线段树和区间加操作是合法的,$0 \le va_i, vb_i, k_i < 2^{32}$。

本题输入量较大,请使用较快的输入方式。

About Issues

We understand that our problem archive is not perfect. If you find any issues with the problem, including the statement, scoring configuration, time/memory limits, test cases, etc.

You may use this form to submit an issue regarding the problem. A problem moderator will review your issue and proceed it properly.

STOP! Before you submit an issue, please READ the following guidelines:

  1. This is not a place to publish a discussion, editorial, or requests to debug your code. Your issue will only be visible by you and problem moderators. Other users will not be able to view or reply your issues.
  2. Do not submit duplicated issues. If you have already submitted one, please wait for an moderator to review it. Submitting multiple issues will not speed up the review process and might cause your account to be banned.
  3. Issues must be filed in English or Chinese only.
  4. Be sure your issue is related to this problem. If you need to submit an issue regarding another problem, contest, category, etc., you should submit it to the corresponding page.

Active Issues 0

No issues in this category.

Closed/Resolved Issues 0

No issues in this category.