[模板]洛谷T3372 线段树 模板1

变量定义:

sum[]:线段树节点对应区间的元素总和;

addv[]:线段树节点对应区间的所有元素的待追加值(懒标记),初值全部设为0。

过程说明:

建树(Build):

若当前节点仅包含原序列中的一个值,即L=R,则直接赋值为序列中该值,否则递归建立左右子树后,将左右子树保存的sum值相加,即得到当前节点的sum值。

懒标记下放(Push_down):

将当前节点的addv值下放到左右子树。

细节实现:

1.子树的addv值加上当前节点的addv值;

2.子树的sum值加上(子树包含元素数量*当前节点的addv值);

3.清空当前节点的addv值,即赋值为0。

特别说明:

1.使用前判断,若当前节点的addv值为0则不需执行此下放函数。虽然执行了也不会有影响,但浪费时间。

2.为尽量节省时间,要将判断放在此函数外而不是函数内。

区间加(update):

若当前节点完全包含在待更新区间内,则直接修改当前节点的addv值和sum值即可;

否则:

1.若当前节点addv值非0,则进行懒标记下放;

2.若待更新区间与左子树对应区间有交集,则递归更新左子树,同理对右子树也执行类似操作。

3.递归更新子树完成后,重新计算当前节点的sum值。

区间查询(query):

若当前节点完全包含在待查询区间内,则直接返回当前节点的sum值;

否则:

1.定义当前节点结果ans=0;

2.若当前节点addv值非0,则进行懒标记下放;

3.若待查询区间与左子树对应区间有交集,则递归查询左子树,并将所得结果加给ans,同理对右子树也执行类似操作。

4.递归查询子树完成后,返回计算好的ans值。

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<ctime>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<algorithm>
 8 #include<string>
 9 #include<stack>
10 #include<queue>
11 #include<vector>
12 #include<map>
13 using namespace std;
14 long long c[2000010];
15 struct sgt{
16     long long sum[2000010];
17     long long addv[2000010];
18     void build(int o,int l,int r){
19         addv[o]=0;
20         if(l==r)sum[o]=c[l];
21         else{
22             int mid=(l+r)>>1;
23             int lson=o<<1;
24             int rson=lson|1;
25             build(lson,l,mid);
26             build(rson,mid+1,r);
27             sum[o]=sum[lson]+sum[rson];
28         }
29     }
30     void push_down(int o,int l,int r,int mid,int lson,int rson){
31         addv[lson]+=addv[o];
32         addv[rson]+=addv[o];
33         sum[lson]+=(mid-l+1)*addv[o];
34         sum[rson]+=(r-mid)*addv[o];
35         addv[o]=0;
36     }
37     void update(int o,int l,int r,int a,int b,int x){
38         if(l>=a && r<=b){
39             addv[o]+=x;
40             sum[o]+=(r-l+1)*x;
41             return;
42         }
43         else{
44             int mid=(l+r)>>1;
45             int lson=o<<1;
46             int rson=lson|1;
47             if(addv[o])push_down(o,l,r,mid,lson,rson);
48             if(a<=mid)update(lson,l,mid,a,b,x);
49             if(b>mid)update(rson,mid+1,r,a,b,x);
50             sum[o]=sum[lson]+sum[rson];
51         }
52     }
53     long long query(int o,int l,int r,int a,int b){
54         if(l>=a && r<=b)return sum[o];
55         else{
56             int mid=(l+r)>>1;
57             int lson=o<<1;
58             int rson=lson|1;
59             long long ans=0;
60             if(addv[o])push_down(o,l,r,mid,lson,rson);
61             if(a<=mid)ans+=query(lson,l,mid,a,b);
62             if(b>mid)ans+=query(rson,mid+1,r,a,b);
63             return ans;
64         }
65     }
66 };
67 sgt tree;
68 int n,m,i,f;
69 int x,y,k;
70 int main(){
71     scanf("%d%d",&n,&m);
72     for(i=1;i<=n;i++)scanf("%d",&c[i]);
73     tree.build(1,1,n);
74     for(i=1;i<=m;i++){
75         scanf("%d",&f);
76         if(f&1){
77             scanf("%d%d%d",&x,&y,&k);
78             tree.update(1,1,n,x,y,k);
79         }
80         else{
81             scanf("%d%d",&x,&y);
82             printf("%lld\n",tree.query(1,1,n,x,y));
83         }
84     }
85     return 0;
86 }
时间: 2024-10-28 11:33:36

[模板]洛谷T3372 线段树 模板1的相关文章

[模板]洛谷T3373 线段树 模板2

此题相对于模板一,加了个区间乘,于是在模板一的基础上需要多开个数组(记录乘法懒标记).多写个函数(区间乘),还有要把懒标记下放函数做些修改. 变量定义: sum[]:线段树节点对应区间的元素总和: addv[]:线段树节点对应区间的所有元素待加的值(懒标记),初值全部设为0: mulv[]:线段树节点对应区间的所有元素待乘的值(懒标记),初值全部设为1. 过程说明: 建树(Build): 同模板一... 懒标记下放(Push_down): 原理解释: 1.当对某区间执行加法操作时,由于加法优先级

洛谷P3372线段树模板1——线段树

题目:https://www.luogu.org/problemnew/show/P3372 线段树模板. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,m,a[100005],ct; struct N{ long long lazy,sum; long long ls,rs; }p[200005]; void pushdown(long long cur,long long l

【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节. 存模板: /* 二维线段树模板整理 */ #include<cstdio> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 805; const int INF = (1 << 30); int n; int posX[max

线段树模板(结构体)

线段树研究了两天了,总算有了点眉目,今天也把落下的题,补了一下. 贴一份线段树模板 线段树的特点: 1. 每一层都是区间[a, b]的一个划分,记 L = b - a 2. 一共有log2L层 3. 给定一个点p,从根到叶子p上的所有区间都包含点p,且其他区间都不包含点p. 4. 给定一个区间[l; r],可以把它分解为不超过2log2 L条不相交线段的并. 总结来说:线段树最近本的应用是4点: 1.单点更新:单点替换.单点增减 2.单点询问 3.区间询问:区间之和.区间最值 4.区间更新:区间

[ACM] 线段树模板

#include<iostream> #include<cmath> using namespace std; #define maxn 200005 class Node{ public: int l,r; int add;//附加值 int sum; }node[maxn]; int getRight(int n){//获得满足2^x>=n的最小x[从0层开始,给编号获得层数] return ceil(log10(n*1.0)/log10(2.0)); } void bu

[POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]

可持久化线段树模板题. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using namespace std; int n,q,tot,a[110000]; in

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

LA 2191电位计(线段树模板题)

线段树模板题,没啥好说的.....注意输出是case之间空一行就行.........之前一直没注意,一直wa 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #includ

P3373 线段树模板

好,这是一个线段树模板. 1 #include <cstdio> 2 using namespace std; 3 const long long int N=1000010; 4 long long int sum[N],tag1[N],tag2[N],mo; 5 6 void build(int l,int r,int o) 7 { 8 tag1[o]=1; 9 if(l==r) 10 { 11 scanf ("%d",&sum[o]); 12 return;