线段树基础总结

线段树几个基本操作

  • 单点查询
  • 单点修改
  • 区间查询
  • 区间修改
  • 区间求最大值

主要思想:

将一个线性的一维数组构建成树形的数组,使得可以用二分的思想来进行区间操作,降低时间复杂度,但是多占用了空间,典型的用空间换时间。

一个特殊的模块:

lazy数组,考虑到对区间的操作有很多次,并且没有必要每一次对区间的操作都更新到点,只需要在需要的时候更新点就可以了。所以用lazy数组来标记一下对该区间里的数进行的操作。

线段树架构:

  • 递归建树便于更新
  • 递归操作同样便于更新

解释代码(以线段树求区间最大值为例,顺便说一下区间求和):

HDU - 1754 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<stack>
  8 #include<deque>
  9 #include<map>
 10 #include<iostream>
 11 using namespace std;
 12 typedef long long  LL;
 13 const double pi=acos(-1.0);
 14 const double e=exp(1);
 15 //const int MAXN =2e5+10;
 16 const int N = 200010*4;
 17 
 18 #define lson i << 1,l,m
 19 #define rson i << 1 | 1,m + 1,r
 20 typedef struct Node
 21 {
 22     LL l;
 23     LL r;
 24     LL mid()
 25     {
 26         return (l+r)/2;
 27     }
 28 } Node;
 29 
 30 LL ans;
 31 Node node[N];
 32 LL add[N];
 33 LL sum[N];
 34 
 35 
 36 //void PushUp(LL i)
 37 //{
 38 //    sum[i]=sum[i<<1]+sum[i<<1 | 1];    //对左右子树进行求和
 39 //}
 40 void PushUp(LL i)
 41 {
 42     sum[i]=max(sum[i<<1],sum[i<<1 | 1]);    //找左右子树的最大值
 43 }
 44 
 45 void build(LL i,LL l,LL r)  
 46 {
 47     node[i].l=l;        //这几行是递,在这个过程中初始化、赋初值
 48     node[i].r=r;
 49     sum[i]=0;
 50     add[i]=0;
 51     if(l==r)
 52     {
 53         scanf("%lld",&sum[i]);      //到达了最后一层的叶子节点,开始取数
 54         return ;
 55     }
 56 
 57     LL m=node[i].mid();     //判断建进左子树还是右子树
 58     build(lson);            
 59     build(rson);
 60     PushUp(i);          //归的过程,对区间进行更新
 61 }
 62 
 63 void PushDown(LL i,LL L)        //add[i]代表的是对区间中的每一个数应该进行的操作,所以他的子节点应该和他一样,且子节点的值应当是区间中数的个数乘以每个数的改变值
 64 {
 65     if(add[i])
 66     {
 67         add[i << 1]+=add[i];
 68         add[i<< 1 | 1]+=add[i];
 69         sum[i << 1]+=add[i]*(L-(L >> 1));
 70         sum[i << 1 | 1]+=add[i]*(L >> 1);
 71         add[i]=0;
 72     }
 73 }
 74 
 75 void line_update(LL v,LL l,LL r,LL i)
 76 {
 77     if(node[i].l==l&&node[i].r==r)      //找到了那个区间(点),进行更新
 78     {
 79         sum[i]+=v*(r-l+1);
 80         add[i]+=v;
 81         return ;
 82     }
 83     //PushDown(i,node[i].r-node[i].l+1);
 84     LL m=node[i].mid();
 85     if(r<=m)
 86         line_update(v,l,r,i <<1);
 87     else
 88     {
 89         if(l>m)
 90             line_update(v,l,r,i<<1 | 1);
 91         else
 92         {
 93             line_update(v,l,m,i << 1);
 94             line_update(v,m+1,r,i << 1 | 1);
 95         }
 96     }
 97     PushUp(i);      //因为点被更新过了,所以要对与他有关都更新
 98 }
 99 
100 LL query(LL l,LL r,LL i)
101 {
102     if(node[i].l==l&&node[i].r==r)
103     {
104         return sum[i];
105     }
106     PushDown(i,node[i].r-node[i].l+1);
107     LL m=node[i].mid();
108     LL ans=0;        //确保最大值是要求区间的
109     if(r<=m)
110         ans=max(query(l,r,i << 1),ans);         
111     else
112     {
113         if(l>m)
114             ans=max(query(l,r,i << 1 | 1),ans);
115         else
116         {
117             ans=max(query(l,m,i << 1),ans);
118             ans=max(query(m+1,r,i << 1 | 1),ans);
119         }
120     }
121     return ans;
122  //   ans=max(ans,sum[i]);
123 }
124 
125 void spot_update(LL v,LL l,LL r,LL i)
126 {
127     if(node[i].l==l&&node[i].r==r)
128     {
129         sum[i]=v;
130         return ;
131     }
132     LL m=node[i].mid();
133     if(r<=m)
134         spot_update(v,l,r,i << 1);
135     else
136     {
137         if(l>m)
138             spot_update(v,l,r,i << 1 | 1);
139         else
140         {
141             spot_update(v,l,m,i << 1);
142             spot_update(v,m+1,r,i << 1 | 1);
143         }
144     }
145     PushUp(i);
146 }
147 
148 int main()
149 {
150     LL n,q,i,p,j,t,m;
151     LL a,b,c;
152     char cc;
153 
154     while(scanf("%lld%lld",&n,&m)!=EOF)
155     {
156         build(1,1,n);
157         while(m--)
158         {
159             scanf(" %c",&cc);
160 
161             if(cc=='Q')
162             {
163                 ans=0;
164                 scanf("%lld%lld",&a,&b);
165                 printf("%lld\n",query(a,b,1));
166             }
167             else if(cc=='U')
168             {
169                 scanf("%lld%lld",&a,&b);
170                 spot_update(b,a,a,1);
171 
172             }
173             getchar();
174         }
175     }
176 
177 //        else if(cc==-1)
178 //        {
179 //            scanf("%lld%lld%lld",&a,&b,&c); //给区间[a,b]+c
180 //            line_update(c,a,b,1);
181 //        }
182 
183     return 0;
184 }

 

posted @ 2018-08-05 21:52  Daybreaking  阅读(162)  评论(0编辑  收藏  举报