线段树的基础递归的使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树的基础递归的使用相关的知识,希望对你有一定的参考价值。
- 问题描述
-
给定n个数列,规定有两种操作,一是修改某个元素,二是求子数列[a,b]的连续和。数列的元素个数最多100000个,询问操作最多100000次。
- 输入
-
第一行2个整数n,m(n表示输入n个数列,m表示有m个操作)
第二行输入n个数列。
接下来M行,每行有三个数k,a,b(k=0表示求子数列[a,b]的和,k=1表示第a个数列加b) - 输出
-
输出若干行数字,表示每次K=0时对应输出一个子数列[a,b]的连续和。
- 输入样列
-
10 5 1 2 3 4 5 6 7 8 9 10 1 1 5 0 1 3 0 4 8 1 7 5 0 4 8
- 输出样例
-
11 30 35
1 //线段树的基本运用 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<string> 7 #define maxn 200000 8 int Sum[maxn*4]; 9 int A[maxn]; 10 int add[maxn]; 11 int n,m; 12 13 using namespace std; 14 15 void PushUp(int rt)//更新本节点 16 { 17 Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; 18 } 19 20 21 void Build(int l,int r,int rt)//构造线段树 22 { 23 if(l==r) 24 { 25 Sum[rt]=A[l]; 26 return ; 27 } 28 int m=(l+r)>>1; 29 Build(l,m,rt<<1); 30 Build(m+1,r,rt<<1|1); 31 PushUp(rt); 32 33 } 34 35 void Update(int L,int C,int l,int r,int rt)//在A[l]+=C 36 {//点修改函数中没有PushDown函数,因为这里假设只有点修改一种操作, 37 //如果题目中是点修改和区间修改混合的话,那么点修改中也需要PushDown。 38 if(l==r) 39 { 40 Sum[rt]+=C; 41 return ; 42 } 43 int m=(l+r)>>1; 44 if(L<=m) Update(L,C,l,m,rt<<1); 45 else Update(L,C,m+1,r,rt<<1|1); 46 PushUp(rt); 47 48 } 49 50 void PushDown(int rt,int ln,int rn)//向下推移标记的函数 51 { 52 //ln,rn为左子树,右子树的数字数量。 53 if(add[rt]) 54 { 55 add[rt<<1]+=add[rt];//下推标记 56 add[rt<<1|1]+=add[rt]; 57 Sum[rt<<1]+=add[rt]*ln; 58 Sum[rt<<1|1]+=add[rt]*rn; 59 add[rt]=0;//清除本节点的标记 60 } 61 } 62 63 void Update_interval(int L,int R,int C,int l,int r,int rt)//在L~R的区间中+C 64 { 65 if(L<=l&&r<=R) 66 { 67 Sum[rt]+=C*(r-l+1); 68 add[rt]+=C; 69 return ; 70 } 71 int m=(l+r)>>1; 72 PushDown(rt,m-l+1,r-m); 73 if(L<=m) Update_interval(L,R,C,l,m,rt<<1); 74 if(R>m) Update_interval(L,R,C,m+1,r,rt<<1|1); 75 PushUp(rt); 76 } 77 78 int Query(int L,int R,int l,int r,int rt)//求和的函数 79 { 80 if(L<=l&&r<=R)//若在区间之内,就直接返回 81 return Sum[rt]; 82 int m=(l+r)>>1; 83 PushDown(rt,m-l+1,r-m); 84 int ans=0; 85 if(L<=m) 86 ans+=Query(L,R,l,m,rt<<1); 87 if(R>m) 88 ans+=Query(L,R,m+1,r,rt<<1|1); 89 return ans; 90 91 } 92 93 int main() 94 { 95 cin>>n;cin>>m; 96 for(int i=1;i<=n;i++) 97 cin>>A[i]; 98 Build(1,n,1); 99 100 int t1,t2,t3; 101 for(int i=1;i<=m;i++) 102 { 103 cin>>t1>>t2>>t3; 104 if(t1&1) Update(t2,t3,1,n,1);//点修改 105 if(t1==0) cout<<Query(t2,t3,1,n,1)<<endl; 106 } 107 return 0; 108 }
参考此位大神的讲解:http://blog.csdn.net/zearot/article/details/48299459
以上是关于线段树的基础递归的使用的主要内容,如果未能解决你的问题,请参考以下文章