1 module dkh.segtree.lazyseg;
2 
3 import dkh.segtree.primitive;
4 
5 import std.functional : binaryFun;
6 
7 /**
8 遅延伝搬SegTree
9 
10 T型の配列aに対して、a[l..r] += x(xはL型)、opTT(a[l..r])が高速に計算できる
11 
12 Params:
13     opTT = (T, T)の演算(結果をまとめる)
14     opTL = (T, L)の演算(クエリを適用する)
15     opLL = (L, L)の演算(クエリをまとめる)
16     eT = Tの単位元
17     eL = Lの単位元
18 */
19 alias LazySeg(T, L, alias opTT, alias opTL, alias opLL, T eT, L eL, alias Engine = LazySegEngine) =
20     SegTree!(Engine, T, L , binaryFun!opTT, binaryFun!opTL, binaryFun!opLL, eT, eL);
21 
22 ///
23 unittest {
24     import std.algorithm : max;
25     ///区間max, 区間加算
26     auto seg = LazySeg!(int, int,
27         (a, b) => max(a, b), (a, b) => a+b, (a, b) => a+b, 0, 0)([2, 1, 4]);
28     
29     //[2, 1, 4]
30     seg[0] = 2; seg[1] = 1; seg[2] = 4;
31     assert(seg[0..3].sum == 4);
32 
33     //[2, 1, 5]
34     seg[2] = 5;
35     assert(seg[0..2].sum == 2);
36     assert(seg[0..3].sum == 5);
37 
38     //[12, 11, 5]
39     seg[0..2] += 10;
40     assert(seg[0..3].sum == 12);
41 }
42 
43 
44 struct LazySegEngine(T, L, alias opTT, alias opTL, alias opLL, T eT, L eL) {
45     import std.typecons : Tuple;
46     alias DataType = T;
47     alias LazyType = L;
48     alias BinSearch = binSearchLazy;
49     alias S = Tuple!(T, "d", L, "lz");
50     uint n, sz, lg;
51     S[] s;
52     this(uint n) {
53         import std.conv : to;
54         import std.algorithm : each;
55         this.n = n;
56         uint lg = 0;
57         while ((2^^lg) < n) lg++;
58         this.lg = lg;
59         sz = 2^^lg;
60         s = new S[](2*sz);
61         s.each!((ref x) => x = S(eT, eL));
62     }
63     this(T[] first) {
64         import std.conv : to;
65         import std.algorithm : each;
66         n = first.length.to!uint;
67         uint lg = 0;
68         while ((2^^lg) < n) lg++;
69         this.lg = lg;
70         sz = 2^^lg;
71 
72         s = new S[](2*sz);
73         s.each!((ref x) => x = S(eT, eL));
74         foreach (i; 0..n) {
75             s[sz+i].d = first[i];
76         }
77         foreach_reverse (i; 1..sz) {
78             update(i);
79         }
80     }
81     @property uint length() const { return n; }
82     pragma(inline):
83     private void lzAdd(uint k, in L x) {
84         s[k].lz = opLL(s[k].lz, x);
85         s[k].d = opTL(s[k].d, x);
86     }
87     public void push(uint k) {
88         if (s[k].lz == eL) return;
89         lzAdd(2*k, s[k].lz);
90         lzAdd(2*k+1, s[k].lz);
91         s[k].lz = eL;
92     }
93     private void update(uint k) {
94         s[k].d = opTT(s[2*k].d, s[2*k+1].d);
95     }
96     T single(uint k) {
97         k += sz;
98         foreach_reverse (uint i; 1..lg+1) {
99             push(k>>i);
100         }
101         return s[k].d;
102     }
103     void singleSet(uint k, T x) {
104         k += sz;
105         foreach_reverse (uint i; 1..lg+1) {
106             push(k>>i);
107         }
108         s[k].d = x;
109         foreach (uint i; 1..lg+1) {
110             update(k>>i);
111         }
112     }
113     T sum(uint a, uint b) {
114         assert(0 <= a && a <= b && b <= n);
115         if (a == b) return eT;
116         a += sz; b--; b += sz;
117         uint tlg = lg;
118         while (true) {
119             uint k = a >> tlg;
120             if (a >> tlg != b >> tlg) {
121                 tlg++;
122                 break;
123             }
124             if (((a-1) >> tlg) + 2 == (b+1) >> tlg) return s[k].d;
125             push(k);
126             tlg--;
127         }
128         T sm = eT;
129         foreach_reverse (l; 0..tlg) {
130             uint k = a >> l;
131             if ((a-1)>>l != a>>l) {
132                 sm = opTT(s[k].d, sm);
133                 break;
134             }
135             push(k);
136             if (!((a >> (l-1)) & 1)) sm = opTT(s[2*k+1].d, sm);
137         }
138         foreach_reverse (l; 0..tlg) {
139             uint k = b >> l;
140             if (b>>l != (b+1)>>l) {
141                 sm = opTT(sm, s[k].d);
142                 break;
143             }
144             push(k);
145             if ((b >> (l-1)) & 1) sm = opTT(sm, s[2*k].d);
146         }
147         return sm;
148     }
149     void add(uint a, uint b, L x) {
150         assert(0 <= a && a <= b && b <= n);
151         if (a == b) return;
152         a += sz; b--; b += sz;
153         uint tlg = lg;
154         while (true) {
155             uint k = a >> tlg;
156             if (a >> tlg != b >> tlg) {
157                 tlg++;
158                 break;
159             }
160             if (((a-1) >> tlg) + 2 == (b+1) >> tlg) {
161                 lzAdd(k, x);
162                 foreach (l; tlg+1..lg+1) {
163                     update(a >> l);
164                 }
165                 return;
166             }
167             push(k);
168             tlg--;
169         }
170         foreach_reverse (l; 0..tlg) {
171             uint k = a >> l;
172             if ((a-1)>>l != a>>l) {
173                 lzAdd(k, x);
174                 foreach (h; l+1..tlg) {
175                     update(a >> h);
176                 }
177                 break;
178             }
179             push(k);
180             if (!((a >> (l-1)) & 1)) lzAdd(2*k+1, x);
181         }
182         foreach_reverse (l; 0..tlg) {
183             uint k = b >> l;
184             if (b>>l != (b+1)>>l) {
185                 lzAdd(k, x);
186                 foreach (h; l+1..tlg) {
187                     update(b >> h);
188                 }
189                 break;
190             }
191             push(k);
192             if ((b >> (l-1)) & 1) lzAdd(2*k, x);
193         }
194         foreach (l; tlg..lg+1) {
195             update(a >> l);
196         }
197     }
198 }
199 
200 
201 
202 unittest {
203     //issue 17466
204     import std.stdio;
205     auto seg = LazySeg!(long[2], long[2],
206         (a, b) => a, (a, b) => a, (a, b) => a, [0L, 0L], [0L, 0L])(10);
207 }
208 
209 
210 int binSearchLazy(bool rev, alias pred, TR)(TR t, int a, int b) {
211     import std.traits : TemplateArgsOf;
212     alias args = TemplateArgsOf!TR;
213     alias opTT = args[2];
214     auto x = args[5];
215     with (t) {
216         static if (!rev) {
217             //left
218             if (pred(x)) return a-1;
219             int pos = a;
220             void f(int a, int b, int l, int r, int k) {
221                 if (b <= l || r <= a) return;
222                 if (a <= l && r <= b && !pred(opTT(x, s[k].d))) {
223                     x = opTT(x, s[k].d);
224                     pos = r;
225                     return;
226                 }
227                 if (l+1 == r) return;
228                 push(k);
229                 int md = (l+r)/2;
230                 f(a, b, l, md, 2*k);
231                 if (pos >= md) f(a, b, md, r, 2*k+1);
232             }
233             f(a, b, 0, sz, 1);
234             return pos;
235         } else {
236             //right
237             if (pred(x)) return b;
238             int pos = b-1;
239             void f(int a, int b, int l, int r, int k) {
240                 if (b <= l || r <= a) return;
241                 if (a <= l && r <= b && !pred(opTT(x, s[k].d))) {
242                     x = opTT(s[k].d, x);
243                     pos = l-1;
244                     return;
245                 }
246                 if (l+1 == r) return;
247                 push(k);
248                 int md = (l+r)/2;
249                 f(a, b, md, r, 2*k+1);
250                 if (pos < md) f(a, b, l, md, 2*k);
251             }
252             f(a, b, 0, sz, 1);
253             return pos;            
254         }
255     }
256 }