线段树
Posted codemaker-li
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。
今天写了线段树,
把以前不会的补了回来,
现在OK了,
一会附上线段树大模板,
各种操作都全了,
先简介一下,
总结出了几个道理:
1 区间加,区间替换的lazy下放不一样,
区间加对于tree[ i ]中的全部元素都 +=
区间替换就是直接赋值
2:lazy的含义是对于一个区间,这个区间完成一个操作,而该区间子区间没有进行该操作,
子区间所有元素 (包括最大值,最小值),都要加入lazy标记,
OK啦
下面是三个模板,最全啦,
操作格子1,是单点替换,区间查询区间和,最大值,最小值,
操作格子2,加上了区间替换为一个数,
操作格子3,加上了区间加一个数,
话不多说,
上代码, ( 代码里有注释,但不能直接提交,要弄明白 )
ps : 305行大代码,累死了
1 #include <cstdio> 2 #include <iostream> 3 #include <bits/stdc++.h> 4 using namespace std; 5 typedef long long ll; 6 typedef unsigned long long ull; 7 8 #define ls (t<<1) 9 #define rs ((t<<1)|1) 10 11 12 #define mk make_pair 13 #define pb push_back 14 #define fi first 15 #define se second 16 17 #define MAXN 500001 18 19 struct tree{ 20 int l,r; 21 ll sum,add,minn,maxx; 22 //可以统计 区间和,区间加,区间最大/小 23 #define l(x) t[x].l 24 #define r(x) t[x].r 25 #define sum(x) t[x].sum 26 #define add(x) t[x].add 27 #define maxx(x) t[x].maxx 28 #define minn(x) t[x].minn 29 tree() { 30 l=r=0; 31 sum=add=minn=maxx=0; 32 } 33 }t[MAXN*4]; 34 35 int a[MAXN]; 36 37 void build(int p,int l,int r) { 38 l(p)=l; 39 r(p)=r; 40 add(p)=0; 41 if (l==r) { 42 sum(p)=a[l]; 43 maxx(p)=a[l]; 44 minn(p)=a[l]; 45 return; 46 } 47 int mid=(l+r)/2; 48 build(p*2,l,mid); 49 build(p*2+1,mid+1,r); 50 sum(p)=sum(p*2)+sum(p*2+1); 51 maxx(p)=max(maxx(p*2),maxx(p*2+1)); 52 minn(p)=min(minn(p*2),minn(p*2+1)); 53 } 54 55 void spread1(int p) { 56 //lazy标记下放与清除 57 //这里lazy用于区间加一个数 58 if (add(p)) { 59 sum(p*2)+=add(p)*(r(p*2)-l(p*2)+1); 60 maxx(p*2)+=add(p); 61 minn(p*2)+=add(p); 62 //更新左节点 63 sum(p*2+1)+=add(p)*(r(p*2+1)-l(p*2+1)+1); 64 maxx(p*2+1)+=add(p); 65 minn(p*2+1)+=add(p); 66 //更新右节点 67 add(p*2)+=add(p); 68 //左节点下放lazy 69 add(p*2+1)+=add(p); 70 //右节点下放lazy 71 add(p)=0; 72 //lazy清空 73 } 74 } 75 void spread2(int p) { 76 //lazy标记下放与清除 77 //这里lazy用于区间替换为一个数 78 if (add(p)) { 79 sum(p*2)=add(p)*(r(p*2)-l(p*2)+1); 80 maxx(p*2)=add(p); 81 minn(p*2)=add(p); 82 //更新左节点 83 sum(p*2+1)=add(p)*(r(p*2+1)-l(p*2+1)+1); 84 maxx(p*2+1)=add(p); 85 minn(p*2+1)=add(p); 86 //更新右节点 87 add(p*2)=add(p); 88 //左节点下放lazy 89 add(p*2+1)=add(p); 90 //右节点下放lazy 91 add(p)=0; 92 //lazy清空 93 } 94 } 95 96 void change1(int p,int l,int r,int d) { 97 //l 到 r 均 +d 98 if (l<=l(p)&&r>=r(p)) { 99 add(p)+=d; 100 sum(p)+=(long long)d*(r(p)-l(p)+1); 101 maxx(p)+=d; 102 minn(p)+=d; 103 return; 104 } 105 spread1(p); 106 //spread2(p); 107 int mid=(l(p)+r(p))/2; 108 if (l<=mid) change1(p*2,l,r,d); 109 if (r>mid) change1(p*2+1,l,r,d); 110 sum(p)=sum(p*2)+sum(p*2+1); 111 maxx(p)=max(maxx(p*2),maxx(p*2+1)); 112 minn(p)=min(minn(p*2),minn(p*2+1)); 113 } 114 115 void change3(int p,int l,int r,int d) { 116 // l~r 均替换为 d 117 if (l<=l(p)&&r>=r(p)) { 118 add(p)=d; 119 sum(p)=(long long)d*(r(p)-l(p)+1); 120 maxx(p)=d; 121 minn(p)=d; 122 return; 123 } 124 //spread1(p); 125 spread2(p); 126 int mid=(l(p)+r(p))/2; 127 if (l<=mid) change3(p*2,l,r,d); 128 if (r>mid) change3(p*2+1,l,r,d); 129 sum(p)=sum(p*2)+sum(p*2+1); 130 maxx(p)=max(maxx(p*2),maxx(p*2+1)); 131 minn(p)=min(minn(p*2),minn(p*2+1)); 132 } 133 134 void change2(int p,int x,int v) { 135 //把 a[x] 值改为 v 136 if (l(p)==r(p)) { 137 //叶子节点直接赋值 138 sum(p)=v; 139 maxx(p)=v; 140 minn(p)=v; 141 return; 142 } 143 spread1(p); 144 //spread2(p); 145 int mid=(l(p)+r(p))/2; 146 if (x<=mid) change2(p*2,x,v); 147 else change2(p*2+1,x,v); 148 sum(p)=sum(p*2)+sum(p*2+1); 149 maxx(p)=max(maxx(p*2),maxx(p*2+1)); 150 minn(p)=min(minn(p*2),minn(p*2+1)); 151 } 152 153 154 ll asksum(int p,int l,int r) { 155 //查询 l~r 的和 156 if (l<=l(p)&&r>=r(p)) return sum(p); 157 //spread1(p); 158 spread2(p); 159 int mid=(l(p)+r(p))/2; 160 ll val=0; 161 if (l<=mid) val+=asksum(p*2,l,r); 162 if (r>mid) val+=asksum(p*2+1,l,r); 163 return val; 164 } 165 166 ll askmax(int p,int l,int r) { 167 //查询 l~r 的最大 168 if (l<=l(p)&&r>=r(p)) return maxx(p); 169 //spread1(p); 170 spread2(p); 171 int mid=(l(p)+r(p))/2; 172 ll val=-(1<<30); 173 if (l<=mid) val=max(val,askmax(p*2,l,r)); 174 if (r>mid) val=max(val,askmax(p*2+1,l,r)); 175 return val; 176 } 177 178 ll askmin(int p,int l,int r) { 179 //查询 l~r 的最小 180 if (l<=l(p)&&r>=r(p)) return minn(p); 181 //spread(p); 182 spread2(p); 183 int mid=(l(p)+r(p))/2; 184 ll val=(1<<30); 185 if (l<=mid) val=min(val,askmin(p*2,l,r)); 186 if (r>mid) val=min(val,askmin(p*2+1,l,r)); 187 return val; 188 } 189 190 /* 191 int n,m; 192 char c; 193 //操作格子1 194 int main() { 195 scanf("%d%d",&n,&m); 196 for (int i=1;i<=n;i++) { 197 scanf("%d",&a[i]); 198 } 199 build(1,1,n); 200 for (int i=1,x,y;i<=m;i++) { 201 cin>>c; 202 scanf("%d%d",&x,&y); 203 if (c==‘Q‘) { 204 ll ansmax=0; 205 ll ansmin=0; 206 ll anssum=0; 207 ansmax=askmax(1,x,y); 208 ansmin=askmin(1,x,y); 209 anssum=asksum(1,x,y); 210 printf("%lld %lld %lld ",ansmax,ansmin,anssum); 211 } 212 if (c==‘U‘) { 213 change2(1,x,y); 214 } 215 } 216 217 return 0; 218 } 219 */ 220 221 /* 222 int n,m; 223 char op[6]; 224 //操作格子3 225 int main () { 226 scanf("%d%d",&n,&m); 227 for (int i=1;i<=n;i++) { 228 scanf("%d",&a[i]); 229 } 230 build(1,1,n); 231 for (int i=1;i<=m;i++) { 232 cin>>op; 233 if (op[0]==‘S‘) { 234 int x,y; 235 scanf("%d%d",&x,&y); 236 ll ans=0; 237 ans=asksum(1,x,y); 238 printf("%lld ",ans); 239 } 240 if (op[0]==‘A‘) { 241 int x,y,z; 242 scanf("%d%d%d",&x,&y,&z); 243 change1(1,x,y,z); 244 } 245 if (op[0]==‘M‘&&op[1]==‘A‘) { 246 int x,y; 247 scanf("%d%d",&x,&y); 248 ll ans=0; 249 ans=askmax(1,x,y); 250 printf("%lld ",ans); 251 } 252 if (op[0]==‘M‘&&op[1]==‘I‘) { 253 int x,y; 254 scanf("%d%d",&x,&y); 255 ll ans=0; 256 ans=askmin(1,x,y); 257 printf("%lld ",ans); 258 } 259 } 260 261 return 0; 262 } 263 */ 264 265 /* 266 int n,m; 267 char op[10]; 268 int main () { 269 scanf("%d%d",&n,&m); 270 for (int i=1;i<=n;i++) { 271 scanf("%d",&a[i]); 272 } 273 build(1,1,n); 274 for (int i=1,x,y,z;i<=m;i++) { 275 cin>>op; 276 if (op[0]==‘S‘) { 277 scanf("%d%d",&x,&y); 278 ll ans=0; 279 ans=asksum(1,x,y); 280 printf("%lld ",ans); 281 } 282 if (op[0]==‘U‘) { 283 scanf("%d%d%d",&x,&y,&z); 284 change3(1,x,y,z); 285 } 286 if (op[0]==‘M‘&&op[1]==‘A‘) { 287 scanf("%d%d",&x,&y); 288 ll ans=0; 289 ans=askmax(1,x,y); 290 printf("%lld ",ans); 291 } 292 if (op[0]==‘M‘&&op[1]==‘I‘) { 293 scanf("%d%d",&x,&y); 294 ll ans=0; 295 ans=askmin(1,x,y); 296 printf("%lld ",ans); 297 } 298 } 299 return 0; 300 } 301 */ 302 303 int main () { 304 return 0; 305 }
以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章