模板——线段树(区间修改)
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.其他方面的问题详见代码