As we all know, algo segment tree is a very important one!
I. Introduction
Segment tree is a binary search tree, and the interval tree is similar, it means a section partitioned into intervals, a leaf node corresponding to each unit section of the segment tree.
Using the segment tree can quickly find a particular node number appearing in a number of line segments, the time complexity of O (logN). Without the optimization of space complexity 2N, 4N in general but also to open an array of practical applications in order to avoid cross-border, and therefore sometimes necessary to make discrete space compression.
II. Use
A single point: Query (query) to modify (add, mul)
Interval: query (and section), modifying the maximum value (max), the minimum value (min) .
III. Implementation
1. achievements
Since each point represents a range, so he has a lot of information (son left, right, son, interval sum) so we keep the structure because then use to mark lazy, so lazy structure there are two markers.
Lazy tag : FIG above example, if you want to 1 - Add a 6 interval, we will pass this information from the root node to the next layer, then add = 2,3 point has a lazy marker 1, so it is said that it has added more than 1, the next time you have to add, then applied directly to the lazy mark. For example, you would earn a sum of money, temporarily do not, there is a bank. If, after solving recursively, then the lazy pass mark on down, and they have to pass after clearing! State (so that the original state is updated subinterval points + the number of pass-ri * lazy marker, (example sum = 5 (its original state) + 4 (the number of section 4, there are added a 2 ) * 2 (labeled lazy)) is metaphysical -------
Multiplication lazy mark (luogu p3373): requires special attention under
For example, originally labeled as lazy 2 + 3
now pass to the next by 8 then becomes (2 + 3) * 8
and then send it a plus three, will become a (2 + 3 + 3) * 8
So we keep so 2 * 8 + 3 * 8
so after 3 plus value is correct!
The Code
% P code is a subject of the request
1 struct Node { 2 int l, r; 3 ll sum; 4 ll add, mul; 5 6 Node() { 7 l = r = sum = add = 0; 8 mul = 1; 9 } 10 11 void update_add(ll value) { 12 add = (add + value) % P; 13 sum = (sum + (r - l + 1) * value) % P; 14 } 15 16 void update_mul(ll value) { 17 sum = (sum * value) % P; 18 mul = (mul * value) % P; 19 add = (add * value) % P; 20 } 21 } t[N << 2];
My contribution may be more strange, when recursion to root again cin, while recursively while updating (push_up, behind)
1 void build_tree(int p, int l, int r) { 2 t[p].l = l, t[p].r = r; 3 if (l == r) { 4 cin >> t[p].sum; 5 return; 6 } 7 int mid = (t[p].l + t[p].r) >> 1; 8 build_tree(lc(p), l, mid); 9 build_tree(rc(p), mid + 1, r); 10 push_up(p); 11 }
Son son left and right
inline int lc(int p) { return p << 1; } inline int rc(int p) { return p << 1 | 1; }
Up push_up update information (sum), down lazy pass mark (push_down) Remember to pass their own state to be restored after Oh!
1 void push_up(int p) { 2 t[p].sum = t[lc(p)].sum + t[rc(p)].sum; 3 } 4 5 void push_down(int p) { 6 if (t[p].mul != 1) { 7 t[lc(p)].update_mul(t[p].mul); 8 t[rc(p)].update_mul(t[p].mul); 9 t[p].mul = 1; 10 } 11 if (t[p].add) { 12 t[lc(p)].update_add(t[p].add); 13 t[rc(p)].update_add(t[p].add); 14 t[p].add = 0; 15 } 16 }
Å%%%Then
When we change the interval
(Black is the total range, red for the need to amend section)
If the current range is a subset of the entire section of the ---- that's fine, you can directly modify
If the current range and total range intersect, then recursively, to find the first fully contained his range, and then modify, and then recursively go up
The Code! ! !
1 void update1(int p, int l, int r, ll value) {//乘法更新 2 if (t[p].l >= l && t[p].r <= r) { 3 t[p].update_mul(value); 4 return; 5 } 6 push_down(p); 7 int mid = (t[p].l + t[p].r) >> 1; 8 if (l <= mid) update1(lc(p), l, r, value); 9 if (r > mid) update1(rc(p), l, r, value); 10 push_up(p); 11 } 12 13 void update2(int p, int l, int r, ll value) {//加法更新 14 if (t[p].l >= l && t[p].r <= r) { 15 t[p].update_add(value); 16 return; 17 } 18 push_down(p); 19 int mid = (t[p].l + t[p].r) >> 1; 20 if (l <= mid) update2(lc(p), l, r, value); 21 if (r > mid) update2(rc(p), l, r, value); 22 push_up(p); 23 } 24 25 ll query(int p, int l, int r) {//区间查询,如果是单点差距的话l == r 26 if (t[p].l >= l && t[p].r <= r) { 27 return t[p].sum % P; 28 } 29 push_down(p); 30 ll sum = 0; 31 int mid = (t[p].l + t[p].r) >> 1; 32 if (l <= mid) sum = (sum + query(lc(p), l, r)) % P; 33 if (r > mid) sum = (sum + query(rc(p), l, r)) % P; 34 return sum % P; 35 }
当然还可以求RMQ问题
1 struct Node 2 { 3 ll minn,maxx; 4 }t[]; 5 6 //build 里加几句 7 t[p].maxx = max(t[lc(p)].maxx,t[rp(p)].maxx); 8 t[p].minn = min(t[lc(p)].minn,t[rp(p)].minn); 9 10 11 int ans1,ans2; 12 void new_query(int p,int l,int r) 13 { 14 if(t[p].l == l && t[p].r == r) 15 { 16 ans1 = max(ans1,t[p].maxx); 17 ans2 = max(ans2,t[p].minn); 18 return; 19 } 20 int mid = (t[p].l + t[p].r) >> 1; 21 if(r <= mid) 22 query(lc(p),l,r); 23 else if (l > mid) 24 query(rc(p),l,r); 25 else 26 { 27 query(lc(p),l,mid); 28 query(rp(p),mid + 1,r); 29 } 30 }
下面附上总代码(代码按照luogu 线段树2的模板打的,可AC)
1 #include <iostream> 2 #include<algorithm> 3 using namespace std; 4 const int N = 1e5 + 7; 5 typedef long long ll; 6 7 ll P; 8 9 struct Node { 10 int l, r; 11 ll sum; 12 ll add, mul; 13 // ll minn,mmax; 14 Node() { 15 l = r = sum = add = 0; 16 mul = 1; 17 } 18 19 void update_add(ll value) { 20 add = (add + value) % P; 21 sum = (sum + (r - l + 1) * value) % P; 22 } 23 24 void update_mul(ll value) { 25 sum = (sum * value) % P; 26 mul = (mul * value) % P; 27 add = (add * value) % P; 28 } 29 } t[N << 2]; 30 31 inline int lc(int p) { 32 return p << 1; 33 } 34 35 inline int rc(int p) { 36 return p << 1 | 1; 37 } 38 39 void push_up(int p) { 40 t[p].sum = t[lc(p)].sum + t[rc(p)].sum; 41 } 42 43 void push_down(int p) { 44 if (t[p].mul != 1) { 45 t[lc(p)].update_mul(t[p].mul); 46 t[rc(p)].update_mul(t[p].mul); 47 t[p].mul = 1; 48 } 49 if (t[p].add) { 50 t[lc(p)].update_add(t[p].add); 51 t[rc(p)].update_add(t[p].add); 52 t[p].add = 0; 53 } 54 } 55 56 void build_tree(int p, int l, int r) { 57 t[p].l = l, t[p].r = r; 58 if (l == r) { 59 cin >> t[p].sum; 60 return; 61 } 62 int mid = (t[p].l + t[p].r) >> 1; 63 build_tree(lc(p), l, mid); 64 build_tree(rc(p), mid + 1, r); 65 // t[p].maxx = max(t[lc(p)].maxx,t[rp(p)].maxx); 66 // t[p].minn = min(t[lc(p)].minn,t[rp(p)].minn); 67 push_up(p); 68 } 69 70 void update1(int p, int l, int r, ll value) { 71 if (t[p].l >= l && t[p].r <= r) { 72 t[p].update_mul(value); 73 return; 74 } 75 push_down(p); 76 int mid = (t[p].l + t[p].r) >> 1; 77 if (l <= mid) update1(lc(p), l, r, value); 78 if (r > mid) update1(rc(p), l, r, value); 79 push_up(p); 80 } 81 82 void update2(int p, int l, int r, ll value) { 83 if (t[p].l >= l && t[p].r <= r) { 84 t[p].update_add(value); 85 return; 86 } 87 push_down(p); 88 int mid = (t[p].l + t[p].r) >> 1; 89 if (l <= mid) update2(lc(p), l, r, value); 90 if (r > mid) update2(rc(p), l, r, value); 91 push_up(p); 92 } 93 94 ll query(int p, int l, int r) { 95 if (t[p].l >= l && t[p].r <= r) { 96 return t[p].sum % P; 97 } 98 push_down(p); 99 ll sum = 0; 100 int mid = (t[p].l + t[p].r) >> 1; 101 if (l <= mid) sum = (sum + query(lc(p), l, r)) % P; 102 if (r > mid) sum = (sum + query(rc(p), l, r)) % P; 103 return sum % P; 104 } 105 /*int ans1,ans2; 106 void new_query(int p,int l,int r) 107 { 108 if(t[p].l == l && t[p].r == r) 109 { 110 ans1 = max(ans1,t[p].maxx); 111 ans2 = max(ans2,t[p].minn); 112 return; 113 } 114 int mid = (t[p].l + t[p].r) >> 1; 115 if(r <= mid) 116 new_query(lc(p),l,r); 117 else if (l > mid) 118 new_query(rc(p),l,r); 119 else 120 { 121 new_query(lc(p),l,mid); 122 new_query(rp(p),mid + 1,r); 123 } 124 } 125 */ 126 127 int main() 128 { 129 int n, m; 130 cin >> n >> m >> P; 131 build_tree(1, 1, n); 132 while (m--) { 133 int op, l, r, num; 134 cin >> op >> l >> r; 135 if (op == 1 || op == 2) cin >> num; 136 if (op == 1) update1(1, l, r, num); 137 else if (op == 2) update2(1, l, r, num); 138 else cout << query(1, l, r) << endl; 139 } 140 } 141 142 //Juddav007 0.0
THANKS FOR WATCHING!