线段树基础总结
线段树几个基本操作
- 单点查询
- 单点修改
- 区间查询
- 区间修改
- 区间求最大值
主要思想:
将一个线性的一维数组构建成树形的数组,使得可以用二分的思想来进行区间操作,降低时间复杂度,但是多占用了空间,典型的用空间换时间。
一个特殊的模块:
lazy数组,考虑到对区间的操作有很多次,并且没有必要每一次对区间的操作都更新到点,只需要在需要的时候更新点就可以了。所以用lazy数组来标记一下对该区间里的数进行的操作。
线段树架构:
- 递归建树便于更新
- 递归操作同样便于更新
解释代码(以线段树求区间最大值为例,顺便说一下区间求和):
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 }