模板——线段树(区间修改)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <assert.h>
 6 using namespace std;
 7 const int maxn = 100000+ 10;
 8 
 9 //update_add:把A[L]~A[R]的值全部加v_add
10 //update_set:把A[l]~A[R]的值设为v_set
11 //query:计算子序列的元素和,最小值,最大值
12 
13 int sumv[2*maxn],minv[2*maxn],maxv[2*maxn];
14 int addv[2*maxn], setv[2*maxn];
15 int y1, y2, v_add, v_set;
16 
17 void maintain(int o, int L, int R) {
18     int lc = 2*o, rc = 2*o + 1;
19     sumv[o] = minv[o] = maxv[o] = 0;
20     if(setv[o] >= 0) {
21         sumv[o] = setv[o] * (R-L+1);
22         minv[o] = maxv[o] = setv[o];
23     }
24     else if(R > L) {
25         sumv[o] = sumv[lc] + sumv[rc];
26         minv[o] = min(minv[lc], minv[rc]);
27         maxv[o] = max(maxv[lc], maxv[rc]);
28     }
29     minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1);
30 }
31 void pushdown(int o) {
32     int lc = 2*o, rc = 2*o+1;
33     if(setv[o] >= 0) {
34         setv[lc] = setv[rc] = setv[o];
35         addv[lc] = addv[rc] = 0;
36         setv[o] = -1;
37     }
38     if(addv[o] > 0) {
39         addv[lc] += addv[o];
40         addv[rc] += addv[o];
41         addv[o] = 0;
42     }
43 }
44 void update_add(int o, int L, int R) {
45     int lc = 2*o, rc = o*2+1;
46     if(y1 <= L && y2 >= R) {
47         addv[o] += v_add;
48     }
49     else {
50         pushdown(o);
51         int M = L + (R-L)/2;
52         if(y1 <= M) update_add(lc, L, M); else maintain(lc, L, M);
53         if(y2 > M) update_add(rc, M+1, R);else maintain(rc, M+1, R);
54     }
55     maintain(o, L, R);
56 }
57 void update_set(int o, int L, int R) {
58     int lc = 2*o, rc = o*2+1;
59     if(y1 <= L && y2 >= R) {
60         setv[o] = v_set;
61         addv[o] = 0;
62     }
63     else {
64         pushdown(o);
65         int M = L + (R-L)/2;
66         if(y1 <= M) update_set(lc, L, M); else maintain(lc, L, M);
67         if(y2 > M) update_set(rc, M+1, R); else maintain(rc, M+1, R);
68     }
69     maintain(o, L, R);
70 }
71 int _min, _max, _sum;
72 void query(int o, int L, int R, int add) {
73     if(setv[o] >= 0) {
74         _sum += (add+setv[o]+addv[o]) * (min(R, y2)-max(L, y1)+1);
75         _min = min(_min, setv[o]+addv[o]+add);
76         _max = max(_max, setv[o]+addv[o]+add);
77     }
78     else if(y1 <= L && y2 >= R) {
79         _sum += sumv[o] + add * (R-L+1);
80         _min = min(_min, minv[o]+add);
81         _max = max(_max, maxv[o]+add);
82     }
83     else {
84         int M = L + (R-L)/2;
85         if(y1 <= M) query(o*2, L, M, add+addv[o]);
86         if(y2 > M) query(o*2+1, M+1, R, add + addv[o]);
87     }
88 }
89 void init() {
90     memset(setv, -1, sizeof setv);
91     memset(addv, 0, sizeof addv);
92     memset(sumv, 0, sizeof sumv);
93     memset(minv, 0, sizeof minv);
94     memset(maxv, 0, sizeof maxv);
95 }

以上代码思路详见白书即(刘汝佳《算法竞赛经典训练指南》)第三章线段树部分,需要注意的是:

  1.set操作时需要将该结点add标识清除

  2.pushdown操作以及maintain操作的位置

  3.其他方面的问题详见代码

 

posted @ 2016-11-09 11:13  kiraa  阅读(3217)  评论(0编辑  收藏  举报