2

洛谷 P3372 【模板】线段树 1 题解

题目描述

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

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

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

输入格式

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

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

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

1.1 x y k:将区间 [x, y] 内每个数加上 k

2.2 x y:输出区间 [x, y] 内每个数的和。

输出格式

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

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,a[500001],add[500001];
 5 long long sum[500001];
 6 
 7 void build(int k,int l,int r)    //建树
 8 {
 9     if (l==r)    //当前为叶节点
10     {
11         sum[k]=a[l];
12         return ;
13     }
14     int mid=(l+r)>>1;
15     build(k*2,l,mid);    //左子树
16     build(k*2+1,mid+1,r);    //右子树
17     sum[k]=sum[k*2]+sum[k*2+1];
18 }
19 
20 void Add(int k,int l,int r,int v)    //区间加值并更新
21 {
22     add[k]+=v;    //打标记
23     sum[k]+=(long long)v*(r-l+1);    //维护区间和
24 }
25 
26 void pushdown(int k,int l,int r,int mid)    //标记下放
27 {
28     if (add[k]==0)    //没有标记
29         return ;
30     else
31     {
32         Add(k*2,l,mid,add[k]);    //下传到左子树
33         Add(k*2+1,mid+1,r,add[k]);    //下传到右子树
34         add[k]=0;    //清零标记
35     }
36 }
37 
38 long long query(int k,int l,int r,int x,int y)    //询问
39 {
40     if (x<=l&&r<=y)
41         return sum[k];
42     int mid=(l+r)>>1;
43     long long ans=0;
44     pushdown(k,l,r,mid);    //下传标记
45     if (x<=mid)
46         ans+=query(k*2,l,mid,x,y);
47     if (mid<y)
48         ans+=query(k*2+1,mid+1,r,x,y);
49     return ans;
50 }
51 
52 void modify(int k,int l,int r,int x,int y,int v)    //区间和
53 {
54     if (x<=l&&r<=y)
55         return Add(k,l,r,v);
56     int mid=(l+r)>>1;
57     pushdown(k,l,r,mid);    //到达每一个结点都要下传标记
58     if (x<=mid)
59         modify(k*2,l,mid,x,y,v);
60     if (mid<y)
61         modify(k*2+1,mid+1,r,x,y,v);
62     sum[k]=sum[k*2]+sum[k*2+1];  //更新下传之后的最新值
63 }
64 
65 int main()
66 {
67     scanf("%d%d",&n,&m);
68     for (int i=1;i<=n;i++)
69         scanf("%d",&a[i]);
70     build(1,1,n);    //建树
71     while (m--)
72     {
73         int op,x,y,v;
74         scanf("%d",&op);
75         if (op==1)    //在x到y的区间内每个数加上v
76         {
77             scanf("%d%d%d",&x,&y,&v);
78             modify(1,1,n,x,y,v);
79         }
80         if (op==2)    //查询x到y的区间和
81         {
82             scanf("%d%d",&x,&y);
83             printf("%lld\n",query(1,1,n,x,y));
84         }
85     }
86     return 0;
87 }

 

再附一份没有注释的代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,a[500001],add[500001];
 5 long long sum[500001];
 6 
 7 void build(int k,int l,int r)
 8 {
 9     if (l==r)
10     {
11         sum[k]=a[l];
12         return ;
13     }
14     int mid=(l+r)>>1;
15     build(k*2,l,mid);
16     build(k*2+1,mid+1,r);
17     sum[k]=sum[k*2]+sum[k*2+1];
18 }
19 
20 void Add(int k,int l,int r,int v)
21 {
22     add[k]+=v;
23     sum[k]+=(long long)v*(r-l+1);
24 }
25 
26 void pushdown(int k,int l,int r,int mid)
27 {
28     if (add[k]==0)
29         return ;
30     else
31     {
32         Add(k*2,l,mid,add[k]);
33         Add(k*2+1,mid+1,r,add[k]);
34         add[k]=0;
35     }
36 }
37 
38 long long query(int k,int l,int r,int x,int y)
39 {
40     if (x<=l&&r<=y)
41         return sum[k];
42     int mid=(l+r)>>1;
43     long long ans=0;
44     pushdown(k,l,r,mid);
45     if (x<=mid)
46         ans+=query(k*2,l,mid,x,y);
47     if (mid<y)
48         ans+=query(k*2+1,mid+1,r,x,y);
49     return ans;
50 }
51 
52 void modify(int k,int l,int r,int x,int y,int v)
53 {
54     if (x<=l&&r<=y)
55         return Add(k,l,r,v);
56     int mid=(l+r)>>1;
57     pushdown(k,l,r,mid);
58     if (x<=mid)
59         modify(k*2,l,mid,x,y,v);
60     if (mid<y)
61         modify(k*2+1,mid+1,r,x,y,v);
62     sum[k]=sum[k*2]+sum[k*2+1];
63 }
64 
65 int main()
66 {
67     scanf("%d%d",&n,&m);
68     for (int i=1;i<=n;i++)
69         scanf("%d",&a[i]);
70     build(1,1,n);
71     while (m--)
72     {
73         int op,x,y,v;
74         scanf("%d",&op);
75         if (op==1)
76         {
77             scanf("%d%d%d",&x,&y,&v);
78             modify(1,1,n,x,y,v);
79         }
80         if (op==2)
81         {
82             scanf("%d%d",&x,&y);
83             printf("%lld\n",query(1,1,n,x,y));
84         }
85     }
86     return 0;
87 }

 

posted @ 2021-08-16 22:01  Zˇx  阅读(70)  评论(0)    收藏  举报
Live2D