题解 P3372 [线段树 1]

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 kk
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [x, y][x,y] 内每个数加上 kk
  2. 2 x y:输出区间 [x, y][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例

输入 #1

5 5

1 5 4 2 3

2 2 4

1 2 3 2

2 3 4

1 1 5 1

2 1 4

输出 #1

11

8

20

说明/提示

对于 30% 的数据:n ≤ 8, m ≤ 10。

对于 70% 的数据:n ≤ 103, m ≤ 104

对于 100% 的数据:1 ≤ n, m ≤ 105

保证任意时刻数列中任意元素的和在 [-263, 263)内

【样例解释】

 

code:

 1 #include <bits/stdc++.h>
 2 #define REP(i, a, b) for (long long i = a; i <= b; ++i)
 3 #define ll long long
 4 #define N 100010
 5 using namespace std;
 6 
 7 ll n, m, a[N];
 8 
 9 struct xcj{
10     ll l, r, value, add;
11     #define l(x) t[x].l
12     #define r(x) t[x].r
13     #define sum(x) t[x].value
14     #define add(x) t[x].add
15 } t[N * 4];
16 
17 inline ll read(){                                                            //快读 
18     ll s = 0, w = 1;
19     char ch = getchar();
20     while (ch < '0' || ch > '9'){
21         if (ch == '-') w *= -1;
22         ch = getchar();
23     }
24     while (ch >= '0' && ch <= '9'){
25         s = s * 10 + ch - '0';
26         ch = getchar();
27     }
28     return s * w;
29 }
30 
31 inline void spread(ll p){ 
32     if (add(p)){                                                            //是否有延迟标记 
33         sum(p * 2) += add(p) * (r(p * 2) - l(p * 2) + 1);                    //更新左儿子的值 
34         sum(p * 2 + 1) += add(p) * (r(p * 2 + 1) - l(p * 2 + 1) + 1);        //更新右儿子的值 
35         add(p * 2) += add(p);                                                //增加左儿子的延迟标记 
36         add(p * 2 + 1) += add(p);                                            //增加右儿子的延迟标记
37         add(p) = 0;                                                            //清除p节点的延迟标记 
38     }
39 }
40 
41 inline void change(ll p, ll l, ll r, ll v){
42     if (l <= l(p) && r >= r(p)){
43         sum(p) += v * (r(p) - l(p) + 1);                                    //加上整棵子树的值 
44         add(p) += v;                                                        //增加延迟标记 
45         return ;
46     }
47     spread(p);
48     ll mid = (l(p) + r(p)) / 2;                                                //取中间值 
49     if (l <= mid) change(p * 2, l, r, v);                                     //区间的左边界是否在左子树中 
50     if (r > mid) change(p * 2 + 1, l, r, v);                                //区间的右边界是否在右子树中 
51     sum(p) = sum(p * 2) + sum(p * 2 + 1);                                    //p节点的值=左儿子的值+右儿子的值 
52 }
53 
54 inline ll ask(ll p, ll l, ll r){                                            //查询 
55     if (l <= l(p) && r >= r(p)) return sum(p);                                //如果完全覆盖就直接返回 
56     spread(p);
57     ll mid = (l(p) + r(p)) / 2, valu = 0;                                    //取中间值
58     if (l <= mid) valu += ask(p * 2, l, r);                                    //区间的左边界是否在左子树中 
59     if (r > mid) valu += ask(p * 2 + 1, l, r);                                //区间的右边界是否在右子树中 
60     return valu;
61 }
62 
63 inline void build(ll p, ll l, ll r){                                        //建树 
64     l(p) = l, r(p) = r;                                                        //判断是否是叶子节点 
65     if (l == r){
66         sum(p) = a[l];
67         return ;
68     }
69     ll mid = (l + r) / 2;
70     build(p * 2, l, mid);                                                    //建左子树 
71     build(p * 2 + 1, mid + 1, r);                                            //建右子树 
72     sum(p) = sum(p * 2) + sum(p * 2 + 1);                                    //p节点的值=左儿子的值+右儿子的值 
73 }
74 
75 inline void init(){                                                            //输入 
76     n = read(), m = read();
77     REP(i, 1, n) a[i] = read();
78 }
79 
80 inline void work(){
81     init();
82     build(1, 1, n);
83     while (m--){
84         ll lyj = read(), l = read(), r = read();
85         if (lyj == 1){                                                        //如果lyj等于1,就执行区间加操作 
86             ll val = read();
87             change(1, l, r, val);
88         } else printf("%lld\n", ask(1, l, r));                                //否则就执行查询操作
89     }
90 }
91 
92 int main(){
93     work();
94     return 0;
95 }

 

posted @ 2020-02-21 12:56  leoair  阅读(67)  评论(0)    收藏  举报