洛谷 P3372 【模板】线段树 加法

题目描述

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

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

 

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

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

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 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

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^,保证在int64/long long数据范围内)

AC代码:

 

 1 #include<iostream>
 2 using namespace std;
 3 long long n,m,a[10000005],p,x,y,pp;
 4 struct kkk{
 5     int l,r;//l、r分别代表此节点所含信息区间左端和右端 
 6     long long add,tql;//add是lazy标记,tql代表此节点所含区间和。 
 7 }t[10000005];
 8 void build(int q,int w,int e) {
 9     t[q].l = w;t[q].r = e;
10     if(w == e) { //如果只维护一个节点的信息,说明为叶节点 
11         t[q].tql = a[w];
12         return ;    
13     } 
14     int mid = w + e >> 1;
15     build(2*q, w, mid);     //建左子树 
16     build(2*q+1, mid+1, e); //建右子树 
17     t[q].tql = t[q*2].tql + t[q*2+1].tql; //一个节点的信息由它的左右儿子得来 
18 }
19 void spr(int o) {//运用lazy标记进行区间修改 
20     if(t[o].add) {
21         t[2*o].tql += t[o].add * (t[2*o].r - t[2*o].l + 1);
22         t[o*2+1].tql += t[o].add * (t[o*2+1].r - t[o*2+1].l + 1);
23         t[o*2].add += t[o].add;
24         t[o*2+1].add += t[o].add;
25         t[o].add = 0;
26     }
27 }
28 void pl(int o,int l,int r,int k) {
29     if(l <= t[o].l && r >= t[o].r) {//如果已知区间被所求全部包含,那么直接计算即可 
30         t[o].tql += (long long) k * (t[o].r - t[o].l + 1);
31         t[o].add += k;
32         return ;
33     }
34     spr(o);
35     int mid = t[o].l + t[o].r >> 1;
36     if(x <= mid) pl(o*2,x,y,k);//如果x<=mid,说明左半区间包含要求区间 
37     if(y > mid) pl(o*2+1,x,y,k); //如果x>=mid ,说明右半区间包含要求区间 
38     t[o].tql = t[o*2].tql + t[o*2+1].tql;
39 }
40 long long pr(int p,int x,int y){
41     if(x <= t[p].l && y >= t[p].r) return t[p].tql;
42     spr(p);
43     int mid = t[p].l + t[p].r >> 1;
44     long long ans = 0;
45     if(x<=mid) ans += pr(p*2,x,y);//如果x<=mid,说明左半子树包含答案 
46     if(y>mid) ans += pr(p*2+1,x,y);//如果x>mid,说明右半子树包含答案 
47     return ans;
48 }
49 int main(){
50     cin >> n >> m;
51     for(int i = 1;i <= n; i++) cin >> a[i];
52     build(1,1,n);//建树 
53     for(int i = 1;i <= m; i++) {
54         cin >> p;
55         if(p == 1) {
56             cin >> x >> y >> pp;
57             pl(1,x, y, pp);
58         }
59         else {
60             cin >> x >> y;
61             cout << pr(1,x,y) << endl;
62         }
63     }
64     
65     return 0;
66 } 

 

posted @ 2019-03-15 21:10  Mr^Simon  阅读(158)  评论(0编辑  收藏  举报