首页 > 代码库 > 线段树的基础递归的使用

线段树的基础递归的使用

问题描述

给定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

线段树的基础递归的使用