diff --git a/datastructure/range_chmin_chmax_add_range_sum/checker.cpp b/datastructure/range_chmin_chmax_add_range_sum/checker.cpp new file mode 100644 index 000000000..6a66d5330 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/checker.cpp @@ -0,0 +1,62 @@ +// https://github.com/MikeMirzayanov/testlib/blob/master/checkers/wcmp.cpp + +// The MIT License (MIT) + +// Copyright (c) 2015 Mike Mirzayanov + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "testlib.h" + +using namespace std; + +int main(int argc, char * argv[]) +{ + setName("compare sequences of tokens"); + registerTestlibCmd(argc, argv); + + int n = 0; + string j, p; + + while (!ans.seekEof() && !ouf.seekEof()) + { + n++; + + ans.readWordTo(j); + ouf.readWordTo(p); + + if (j != p) + quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), compress(j).c_str(), compress(p).c_str()); + } + + if (ans.seekEof() && ouf.seekEof()) + { + if (n == 1) + quitf(_ok, "\"%s\"", compress(j).c_str()); + else + quitf(_ok, "%d tokens", n); + } + else + { + if (ans.seekEof()) + quitf(_wa, "Participant output contains extra tokens"); + else + quitf(_wa, "Unexpected EOF in the participants output"); + } +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/gen/example_00.in b/datastructure/range_chmin_chmax_add_range_sum/gen/example_00.in new file mode 100644 index 000000000..02b50be15 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/gen/example_00.in @@ -0,0 +1,9 @@ +5 7 +1 2 3 4 5 +3 0 5 +2 2 4 100 +3 0 3 +0 1 3 10 +3 2 5 +1 2 5 20 +3 0 5 diff --git a/datastructure/range_chmin_chmax_add_range_sum/gen/max_random.cpp b/datastructure/range_chmin_chmax_add_range_sum/gen/max_random.cpp new file mode 100644 index 000000000..7d3f10ac9 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/gen/max_random.cpp @@ -0,0 +1,49 @@ +#include "random.h" +#include +#include +#include +#include "../params.h" +#include "../segtree.hpp" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_AND_Q_MAX; + int q = N_AND_Q_MAX; + printf("%d %d\n", n, q); + vector init(n); + for (int i = 0; i < n; i++) { + long long a = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%lld", a); + if (i != n - 1) printf(" "); + init[i] = { a, a }; + } + printf("\n"); + chmin_chmax_add_min_max_segment_tree segtree(init.begin(), init.end()); + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 3); + int l, r; + tie(l, r) = gen.uniform_pair(0, n); + if (t == 0) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { b, LLONG_MIN, 0ll }); + } else if (t == 1) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, b, 0ll }); + } else if (t == 2) { + auto c = segtree.range_get(0, n); + long long b = gen.uniform(-A_ABS_MAX - c.min, A_ABS_MAX - c.max); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, LLONG_MIN, b }); + printf("%d %d %d %lld\n", t, l, r, b); + } else { + printf("%d %d %d\n", t, l, r); + } + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/gen/medium.cpp b/datastructure/range_chmin_chmax_add_range_sum/gen/medium.cpp new file mode 100644 index 000000000..c97d428c0 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/gen/medium.cpp @@ -0,0 +1,49 @@ +#include "random.h" +#include +#include +#include +#include "../params.h" +#include "../segtree.hpp" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(1, 2000); + int q = gen.uniform(1, 2000); + printf("%d %d\n", n, q); + vector init(n); + for (int i = 0; i < n; i++) { + long long a = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%lld", a); + if (i != n - 1) printf(" "); + init[i] = { a, a }; + } + printf("\n"); + chmin_chmax_add_min_max_segment_tree segtree(init.begin(), init.end()); + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 3); + int l, r; + tie(l, r) = gen.uniform_pair(0, n); + if (t == 0) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { b, LLONG_MIN, 0ll }); + } else if (t == 1) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, b, 0ll }); + } else if (t == 2) { + auto c = segtree.range_get(0, n); + long long b = gen.uniform(-A_ABS_MAX - c.min, A_ABS_MAX - c.max); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, LLONG_MIN, b }); + printf("%d %d %d %lld\n", t, l, r, b); + } else { + printf("%d %d %d\n", t, l, r); + } + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/gen/random.cpp b/datastructure/range_chmin_chmax_add_range_sum/gen/random.cpp new file mode 100644 index 000000000..980b4426a --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/gen/random.cpp @@ -0,0 +1,49 @@ +#include "random.h" +#include +#include +#include +#include "../params.h" +#include "../segtree.hpp" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(1, N_AND_Q_MAX); + int q = gen.uniform(1, N_AND_Q_MAX); + printf("%d %d\n", n, q); + vector init(n); + for (int i = 0; i < n; i++) { + long long a = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%lld", a); + if (i != n - 1) printf(" "); + init[i] = { a, a }; + } + printf("\n"); + chmin_chmax_add_min_max_segment_tree segtree(init.begin(), init.end()); + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 3); + int l, r; + tie(l, r) = gen.uniform_pair(0, n); + if (t == 0) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { b, LLONG_MIN, 0ll }); + } else if (t == 1) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, b, 0ll }); + } else if (t == 2) { + auto c = segtree.range_get(0, n); + long long b = gen.uniform(-A_ABS_MAX - c.min, A_ABS_MAX - c.max); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, LLONG_MIN, b }); + printf("%d %d %d %lld\n", t, l, r, b); + } else { + printf("%d %d %d\n", t, l, r); + } + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/gen/small.cpp b/datastructure/range_chmin_chmax_add_range_sum/gen/small.cpp new file mode 100644 index 000000000..104f28b8f --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/gen/small.cpp @@ -0,0 +1,51 @@ +#include "random.h" +#include +#include +#include +#include +#include "../params.h" +#include "../segtree.hpp" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + assert (0 <= seed and seed < 10); + int n = seed + 1; // use the seed, which is an index in the test set, to check n = 2^k - 1, 2^k, 2^k + 1 + int q = 20; + printf("%d %d\n", n, q); + vector init(n); + for (int i = 0; i < n; i++) { + long long a = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%lld", a); + if (i != n - 1) printf(" "); + init[i] = { a, a }; + } + printf("\n"); + chmin_chmax_add_min_max_segment_tree segtree(init.begin(), init.end()); + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 3); + int l, r; + tie(l, r) = gen.uniform_pair(0, n); + if (t == 0) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { b, LLONG_MIN, 0ll }); + } else if (t == 1) { + long long b = gen.uniform(-A_ABS_MAX, A_ABS_MAX); + printf("%d %d %d %lld\n", t, l, r, b); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, b, 0ll }); + } else if (t == 2) { + auto c = segtree.range_get(0, n); + long long b = gen.uniform(-A_ABS_MAX - c.min, A_ABS_MAX - c.max); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, LLONG_MIN, b }); + printf("%d %d %d %lld\n", t, l, r, b); + } else { + printf("%d %d %d\n", t, l, r); + } + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/hash.json b/datastructure/range_chmin_chmax_add_range_sum/hash.json new file mode 100644 index 000000000..95b30fa95 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/hash.json @@ -0,0 +1,42 @@ +{ + "example_00.in": "8691e362b7409e5566abe9cdf2ba2d1659b46edef70dabbe485f750c3f185cfc", + "example_00.out": "a98cad4d512832ba33f51cab84fb6a1a91ebccda726f28a96b95fbb5eb04caba", + "max_random_00.in": "ff61ec3451c08c4b5869fb10790219890c75997aaa08c3e4acbb861a772629f6", + "max_random_00.out": "55a36ec8b7f35c71059a9718718aab35eb07e0df0a2daf0ba314f66eebd601a9", + "max_random_01.in": "07e19c435e1567726dce1d5985b1b2f071884a1e7a9c8202ea75de2b92be1bc0", + "max_random_01.out": "2097dce17a09127030554cf84ccd66a399ff04083e8c06159f55e733fb26aa6e", + "max_random_02.in": "810d787363136ffdd593a0e8aa4bda2187c1b548496ad59a723aa480a3d6ebe8", + "max_random_02.out": "64ce401d418c90d409c6c7069b3a687e6f36fccfb2b6cf68b50b1904b2ab45e9", + "medium_00.in": "b82c5f3d284553fb5459f027889154a91f0e81b274e7df6a9097af31e71f06a4", + "medium_00.out": "df700404f1236f92470ad1b87e792d34c9e032b9a48b515ad18ee0ba6e48b448", + "medium_01.in": "468020ca164fca4b89e776c705793351fa420da9aec2e0d4c58e202ebd28412b", + "medium_01.out": "e1bfa5ca74fbefd6610dbfd2242808875b8df3fe0caa6770701986c0905dd47b", + "medium_02.in": "c6f6af721973a3770f765aac130a13b87ea62a2208078dfcbcb15f6326d15477", + "medium_02.out": "179fa759d150c55cc92ccfb1cb4377a1ca99415cf685c42521e2d43eb2fa0ace", + "random_00.in": "24f2355fb51920344ebdd7f2ae1067ebde3978ff4e587c29687b948c3d3cd938", + "random_00.out": "26ced9d66730e5a7cff158a4df1d101d30918d96112a95abb289a7b2c1c442b2", + "random_01.in": "c7680196b6ba9c0c2e38e4f808abd076b203d662b854e49a71c057070ff1fac3", + "random_01.out": "e3a4a7093ac8d98e9eaa68d31f7a987d87e8c7eefa29de46f7336d76305787c7", + "random_02.in": "6764d8efa25481cbae5a11e6fe20feb4f9e8f63f4001644868df40e8d5703d0e", + "random_02.out": "3e72541cf521161620fbc7801172c1f4c1b256f6fc1ed3e80798784372b9a4a6", + "small_00.in": "a55a5fe923e9cfd4b6fc86f4d1fa6524ef58d2e00805f57a3a87a4f2e0195b4a", + "small_00.out": "6088af775600493389506c87350d8a8e292826f5c1d1dc19bbb5f7a1065952e6", + "small_01.in": "ef075086c922bfe337c0e3fbd4d1d7bd37a4e4854e9092c7bd718c764127595b", + "small_01.out": "21fa8fc9319dda4572b130e745aa2ffe81ca4deb3cbdae4d3865fbbe313fbb73", + "small_02.in": "77d59563adb078370fd91b4c5b9b6902b4d0e929f37998eb06fcf5216c0a134e", + "small_02.out": "503618eaa7a866f70ae46dc4d420808e064abd4ecd3d6c6a1e90a77d0400173b", + "small_03.in": "406feb996eeab64740ea3cb9df8685052dee08533306b78c359e2716762fbe67", + "small_03.out": "5494425d43b40baefd2e304f6a77d0316e2fd1cd79c7b25d012d50aa3df42d82", + "small_04.in": "88abc6f643e49add33082ae38954ee1b9a07f99c15aabea61355c9df7678b6dc", + "small_04.out": "35be01a9eda5f3c9648b67428bfa83da4cc3f8fb429020304ba8dfa056ee2664", + "small_05.in": "15ec25bebea4618e09c6acf124c8c226bb3e07bbdbe209899082534aa3d10ba3", + "small_05.out": "8ad17c34388ab2ca7f2ef72853dd852294d7ee10b484ade1d36f4c72d32cb124", + "small_06.in": "f2547c1acd50f28ec8883ab3726e5fe05d1064a227c6ae2f07d4c63e69b95443", + "small_06.out": "ed936a67f1657642e8073e21f95103196229cc77455d6482ebd59a08c912cfc9", + "small_07.in": "ece284376fe38557c8080bfd1de0f356d453ebad583918cd8c5da57eec147d29", + "small_07.out": "3a3d997f842b7e88643c56a04e69ad0bcebe8e84de7687fc505970b2eb8f7490", + "small_08.in": "de54614c264210e47609898635bcfb6440f059a0895a1a078c2d831ef7a732eb", + "small_08.out": "f1270aed58f4d85cde341cfcdb81773760f0e9609bc6764bfc2fca05d8d229c3", + "small_09.in": "9e7e4fe32e402a6a5a928a8ef9531fcebf201f04eac1f222f1aa47d2cf842a70", + "small_09.out": "50bac94959608ff81cfdc25cca9b674fd9fe38f1c8bb3ea50c031339f1d6acdc" +} \ No newline at end of file diff --git a/datastructure/range_chmin_chmax_add_range_sum/info.toml b/datastructure/range_chmin_chmax_add_range_sum/info.toml new file mode 100644 index 000000000..6646ec8fa --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/info.toml @@ -0,0 +1,27 @@ +title = 'Range Chmin Chmax Add Range Sum' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/243" +[[tests]] + name = "example.in" + number = 1 + +[[tests]] + name = "small.cpp" + number = 10 +[[tests]] + name = "medium.cpp" + number = 3 +[[tests]] + name = "random.cpp" + number = 3 +[[tests]] + name = "max_random.cpp" + number = 3 + +[[solutions]] + name = "naive.cpp" + wrong = true + +[params] + N_AND_Q_MAX = 500_000 + A_ABS_MAX = 1_000_000_000_000 diff --git a/datastructure/range_chmin_chmax_add_range_sum/segtree.hpp b/datastructure/range_chmin_chmax_add_range_sum/segtree.hpp new file mode 100644 index 000000000..f013edacf --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/segtree.hpp @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include +#include +#include + +template +struct lazy_propagation_segment_tree { + typedef typename MonoidX::value_type value_type; + typedef typename MonoidF::value_type operator_type; + const MonoidX mon_x; + const MonoidF mon_f; + const Action act; + int n; + std::vector a; + std::vector f; + + lazy_propagation_segment_tree() = default; + lazy_propagation_segment_tree(int n_, const MonoidX & mon_x_ = MonoidX(), const MonoidF & mon_f_ = MonoidF(), const Action & act_ = Action()) + : mon_x(mon_x_), mon_f(mon_f_), act(act_) { + n = 1; while (n < n_) n *= 2; + a.resize(2 * n - 1, mon_x.unit()); + f.resize(n - 1, mon_f.unit()); + } + template + lazy_propagation_segment_tree(InputIterator first, InputIterator last, const MonoidX & mon_x_ = MonoidX(), const MonoidF & mon_f_ = MonoidF(), const Action & act_ = Action()) + : mon_x(mon_x_), mon_f(mon_f_), act(act_) { + int size = std::distance(first, last); + n = 1; while (n < size) n *= 2; + a.resize(2 * n - 1, mon_x.unit()); + f.resize(n - 1, mon_f.unit()); + std::copy(first, last, a.begin() + (n - 1)); + for (int i = n - 2; i >= 0; -- i) { + a[i] = mon_x.mult(a[2 * i + 1], a[2 * i + 2]); + } + } + + void range_apply(int l, int r, operator_type g) { + assert (0 <= l and l <= r and r <= n); + range_apply(0, 0, n, l, r, g); + } + void range_apply(int i, int il, int ir, int l, int r, operator_type g) { + if (l <= il and ir <= r) { // 0-based + a[i] = act(g, a[i]); + if (i < (int)f.size()) f[i] = mon_f.mult(g, f[i]); + } else if (ir <= l or r <= il) { + // nop + } else { + range_apply(2 * i + 1, il, (il + ir) / 2, 0, n, f[i]); + range_apply(2 * i + 2, (il + ir) / 2, ir, 0, n, f[i]); + f[i] = mon_f.unit(); // unnecessary if the oprator monoid is commutative + range_apply(2 * i + 1, il, (il + ir) / 2, l, r, g); + range_apply(2 * i + 2, (il + ir) / 2, ir, l, r, g); + a[i] = mon_x.mult(a[2 * i + 1], a[2 * i + 2]); + } + } + + value_type range_get(int l, int r) { + assert (0 <= l and l <= r and r <= n); + if (l == 0 and r == n) return a[0]; + value_type lacc = mon_x.unit(), racc = mon_x.unit(); + for (int l1 = (l += n), r1 = (r += n) - 1; l1 > 1; l /= 2, r /= 2, l1 /= 2, r1 /= 2) { // 1-based loop, 2x faster than recursion + if (l < r) { + if (l % 2 == 1) lacc = mon_x.mult(lacc, a[(l ++) - 1]); + if (r % 2 == 1) racc = mon_x.mult(a[(-- r) - 1], racc); + } + lacc = act(f[l1 / 2 - 1], lacc); + racc = act(f[r1 / 2 - 1], racc); + } + return mon_x.mult(lacc, racc); + } +}; + +struct min_max_monoid { + struct value_type { + long long min; + long long max; + }; + value_type unit() const { + return (value_type) { LLONG_MAX, LLONG_MIN }; + } + value_type mult(value_type a, value_type b) const { + return (value_type) { std::min(a.min, b.min), std::max(a.max, b.max) }; + } +}; + +struct chmin_chmax_add_monoid { + // lambda x: min(a, max(b, c + x)) + struct value_type { + long long chmin; + long long chmax; + long long add; + }; + value_type unit() const { + return (value_type) { LLONG_MAX, LLONG_MIN, 0ll }; + } + value_type mult(value_type a, value_type b) const { + value_type c = b; + // add + if (c.chmin != LLONG_MAX) { + c.chmin += a.add; + } + if (c.chmax != LLONG_MIN) { + c.chmax += a.add; + } + c.add += a.add; + // chmax + c.chmin = std::max(a.chmax, c.chmin); + c.chmax = std::max(a.chmax, c.chmax); + // chmin + c.chmin = std::min(a.chmin, c.chmin); + return c; + } +}; + +struct chmin_chmax_add_min_max_action { + typedef typename chmin_chmax_add_monoid::value_type F; + typedef typename min_max_monoid::value_type X; + X operator () (F f, X x) const { + if (x.min == LLONG_MAX) { + assert (x.max == LLONG_MIN); + return x; + } + X y; + y.min = std::min(f.chmin, std::max(f.chmax, f.add + x.min)); + y.max = std::min(f.chmin, std::max(f.chmax, f.add + x.max)); + return y; + } +}; + +typedef lazy_propagation_segment_tree chmin_chmax_add_min_max_segment_tree; diff --git a/datastructure/range_chmin_chmax_add_range_sum/sol/correct.cpp b/datastructure/range_chmin_chmax_add_range_sum/sol/correct.cpp new file mode 100644 index 000000000..297953483 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/sol/correct.cpp @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i)) +#define REP3(i, m, n) for (int i = (m); (i) < (int)(n); ++ (i)) +#define REP_R(i, n) for (int i = (int)(n) - 1; (i) >= 0; -- (i)) +#define REP3R(i, m, n) for (int i = (int)(n) - 1; (i) >= (int)(m); -- (i)) +#define ALL(x) std::begin(x), std::end(x) + +/** + * @brief a segment tree beats + */ +class segment_tree_beats { + // MEMO: values for queries (max, min, lazy_add, and lazy_update) already apply to the current node; but not for children + typedef struct { + int64_t max; + int64_t max_second; + int max_count; + int64_t min; + int64_t min_second; + int min_count; + int64_t lazy_add; + int64_t lazy_update; + int64_t sum; + } value_type; + + int n; + std::vector a; + +public: + segment_tree_beats() = default; + segment_tree_beats(int n_) { + n = 1; while (n < n_) n *= 2; + a.resize(2 * n - 1); + tag(0, 0); + } + template + segment_tree_beats(InputIterator first, InputIterator last) { + int n_ = std::distance(first, last); + n = 1; while (n < n_) n *= 2; + a.resize(2 * n - 1); + REP (i, n_) { + tag(n - 1 + i, *(first + i)); + } + REP3 (i, n_, n) { + tag(n - 1 + i, 0); + } + REP_R (i, n - 1) { + update(i); + } + } + + void range_chmin(int l, int r, int64_t value) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + range_apply(0, 0, n, l, r, value); + } + void range_chmax(int l, int r, int64_t value) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + range_apply(0, 0, n, l, r, value); + } + void range_add(int l, int r, int64_t value) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + range_apply(0, 0, n, l, r, value); + } + void range_update(int l, int r, int64_t value) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + range_apply(0, 0, n, l, r, value); + } + + int64_t range_min(int l, int r) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + return range_get(0, 0, n, l, r); + } + int64_t range_max(int l, int r) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + return range_get(0, 0, n, l, r); + } + int64_t range_sum(int l, int r) { // 0-based, [l, r) + assert (0 <= l and l <= r and r <= n); + return range_get(0, 0, n, l, r); + } + +private: + static constexpr char CHMIN = 0; + static constexpr char CHMAX = 1; + static constexpr char ADD = 2; + static constexpr char UPDATE = 3; + static constexpr char MIN = 10; + static constexpr char MAX = 11; + static constexpr char SUM = 12; + + template + void range_apply(int i, int il, int ir, int l, int r, int64_t g) { + if (ir <= l or r <= il or break_condition(i, g)) { + // break + } else if (l <= il and ir <= r and tag_condition(i, g)) { + tag(i, g); + } else { + pushdown(i); + range_apply(2 * i + 1, il, (il + ir) / 2, l, r, g); + range_apply(2 * i + 2, (il + ir) / 2, ir, l, r, g); + update(i); + } + } + template + inline bool break_condition(int i, int64_t g) { + switch (TYPE) { + case CHMIN: return a[i].max <= g; + case CHMAX: return g <= a[i].min; + case ADD: return false; + case UPDATE: return false; + default: assert (false); + } + } + template + inline bool tag_condition(int i, int64_t g) { + switch (TYPE) { + case CHMIN: return a[i].max_second < g and g < a[i].max; + case CHMAX: return a[i].min < g and g < a[i].min_second; + case ADD: return true; + case UPDATE: return true; + default: assert (false); + } + } + template + inline void tag(int i, int64_t g) { + int length = n >> (32 - __builtin_clz(i + 1) - 1); + if (TYPE == CHMIN) { + if (a[i].max == a[i].min or g <= a[i].min) { + tag(i, g); + return; + } + if (a[i].max != INT64_MIN) { + a[i].sum -= a[i].max * a[i].max_count; + } + a[i].max = g; + a[i].min_second = std::min(a[i].min_second, g); + if (a[i].lazy_update != INT64_MAX) { + a[i].lazy_update = std::min(a[i].lazy_update, g); + } + a[i].sum += g * a[i].max_count; + } else if (TYPE == CHMAX) { + if (a[i].max == a[i].min or a[i].max <= g) { + tag(i, g); + return; + } + if (a[i].min != INT64_MAX) { + a[i].sum -= a[i].min * a[i].min_count; + } + a[i].min = g; + a[i].max_second = std::max(a[i].max_second, g); + if (a[i].lazy_update != INT64_MAX) { + a[i].lazy_update = std::max(a[i].lazy_update, g); + } + a[i].sum += g * a[i].min_count; + } else if (TYPE == ADD) { + if (a[i].max != INT64_MAX) { + a[i].max += g; + } + if (a[i].max_second != INT64_MIN) { + a[i].max_second += g; + } + if (a[i].min != INT64_MIN) { + a[i].min += g; + } + if (a[i].min_second != INT64_MAX) { + a[i].min_second += g; + } + a[i].lazy_add += g; + if (a[i].lazy_update != INT64_MAX) { + a[i].lazy_update += g; + } + a[i].sum += g * length; + } else if (TYPE == UPDATE) { + a[i].max = g; + a[i].max_second = INT64_MIN; + a[i].max_count = length; + a[i].min = g; + a[i].min_second = INT64_MAX; + a[i].min_count = length; + a[i].lazy_add = 0; + a[i].lazy_update = INT64_MAX; + a[i].sum = g * length; + } else { + assert (false); + } + } + void pushdown(int i) { + int l = 2 * i + 1; + int r = 2 * i + 2; + // update + if (a[i].lazy_update != INT64_MAX) { + tag(l, a[i].lazy_update); + tag(r, a[i].lazy_update); + a[i].lazy_update = INT64_MAX; + return; + } + // add + if (a[i].lazy_add != 0) { + tag(l, a[i].lazy_add); + tag(r, a[i].lazy_add); + a[i].lazy_add = 0; + } + // chmin + if (a[i].max < a[l].max) { + tag(l, a[i].max); + } + if (a[i].max < a[r].max) { + tag(r, a[i].max); + } + // chmax + if (a[l].min < a[i].min) { + tag(l, a[i].min); + } + if (a[r].min < a[i].min) { + tag(r, a[i].min); + } + } + void update(int i) { + int l = 2 * i + 1; + int r = 2 * i + 2; + // chmin + std::vector b { a[l].max, a[l].max_second, a[r].max, a[r].max_second }; + std::sort(b.rbegin(), b.rend()); + b.erase(std::unique(ALL(b)), b.end()); + a[i].max = b[0]; + a[i].max_second = b[1]; + a[i].max_count = (b[0] == a[l].max ? a[l].max_count : 0) + (b[0] == a[r].max ? a[r].max_count : 0); + // chmax + std::vector c { a[l].min, a[l].min_second, a[r].min, a[r].min_second }; + std::sort(ALL(c)); + c.erase(std::unique(ALL(c)), c.end()); + a[i].min = c[0]; + a[i].min_second = c[1]; + a[i].min_count = (c[0] == a[l].min ? a[l].min_count : 0) + (c[0] == a[r].min ? a[r].min_count : 0); + // add + a[i].lazy_add = 0; + // update + a[i].lazy_update = INT64_MAX; + // sum + a[i].sum = a[l].sum + a[r].sum; + } + + template + int64_t range_get(int i, int il, int ir, int l, int r) { + if (ir <= l or r <= il) { + return 0; + } else if (l <= il and ir <= r) { + // base + switch (TYPE) { + case MIN: return a[i].min; + case MAX: return a[i].max; + case SUM: return a[i].sum; + default: assert (false); + } + } else { + pushdown(i); + int64_t value_l = range_get(2 * i + 1, il, (il + ir) / 2, l, r); + int64_t value_r = range_get(2 * i + 2, (il + ir) / 2, ir, l, r); + // mult + switch (TYPE) { + case MIN: return std::min(value_l, value_r); + case MAX: return std::max(value_l, value_r); + case SUM: return value_l + value_r; + default: assert (false); + } + } + } +}; + +int main() { + int n, q; scanf("%d%d", &n, &q); + + std::vector a(n); + for (int i = 0; i < n; i++) { + scanf("%lld", &a[i]); + } + segment_tree_beats beats(ALL(a)); + + for (int ph = 0; ph < q; ph++) { + int ty, l, r; scanf("%d%d%d", &ty, &l, &r); + if (ty == 0) { + long long b; scanf("%lld", &b); + beats.range_chmin(l, r, b); + } else if (ty == 1) { + long long b; scanf("%lld", &b); + beats.range_chmax(l, r, b); + } else if (ty == 2) { + long long b; scanf("%lld", &b); + beats.range_add(l, r, b); + } else { + long long sum = beats.range_sum(l, r); + printf("%lld\n", sum); + } + + assert (-1'000'000'000'000 <= beats.range_min(0, n)); + assert (beats.range_max(0, n) <= 1'000'000'000'000); + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/sol/naive.cpp b/datastructure/range_chmin_chmax_add_range_sum/sol/naive.cpp new file mode 100644 index 000000000..047574dbb --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/sol/naive.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +using namespace std; +using uint = unsigned int; +using ll = long long; +using ull = unsigned long long; +constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n - 1); } +template using V = vector; +template using VV = V>; + +int main() { + int n, q; + scanf("%d%d", &n, &q); + assert(ll(n) * q <= TEN(8)); + + vector a(n); + for (int i = 0; i < n; i++) { + scanf("%lld", &a[i]); + assert (llabs(a[i]) <= TEN(12)); + } + + for (int ph = 0; ph < q; ph++) { + int ty, l, r; + scanf("%d%d%d", &ty, &l, &r); + if (ty == 0) { + ll b; + scanf("%lld", &b); + assert (llabs(b) <= TEN(12)); + for (int i = l; i < r; i++) { + a[i] = min(a[i], b); + } + } else if (ty == 1) { + ll b; + scanf("%lld", &b); + assert (llabs(b) <= TEN(12)); + for (int i = l; i < r; i++) { + a[i] = max(a[i], b); + } + } else if (ty == 2) { + ll b; + scanf("%lld", &b); + for (int i = l; i < r; i++) { + a[i] += b; + assert (llabs(a[i]) <= TEN(12)); + } + } else { + ll sum = 0; + for (int i = l; i < r; i++) { + sum += a[i]; + } + printf("%lld\n", sum); + } + } + return 0; +} diff --git a/datastructure/range_chmin_chmax_add_range_sum/task.md b/datastructure/range_chmin_chmax_add_range_sum/task.md new file mode 100644 index 000000000..c872129b5 --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/task.md @@ -0,0 +1,30 @@ +問題文 +--------- + +長さ $N$ の整数列 $a_0, a_1, \dots, a _ {N - 1}$ が与えられる。$Q$ 個のクエリが飛んでくるので処理せよ。 + +- `0 $l$ $r$ $b$`: $i = l, \dots, {r-1}$ のそれぞれについて $a_i = \min(a_i, b)$ +- `1 $l$ $r$ $b$`: $i = l, \dots, {r-1}$ のそれぞれについて $a_i = \max(a_i, b)$ +- `2 $l$ $r$ $b$`: $i = l, \dots, {r-1}$ のそれぞれについて $a_i = a_i + b$ +- `3 $l$ $r$`: $\sum _ {i = l} ^ {r-1} a_i$ を出力 + +制約 +--------- + +- $1 \leq N, Q \leq {{param N_AND_Q_MAX}}$ +- クエリ処理の過程で常に $\vert a_i \vert \leq {{param A_ABS_MAX}}$ が成り立つ +- $0 \leq l < r \leq N$ + +入力 +--------- + +~~~ +$N$ $Q$ +$a_0$ $a_1$ ... $a_{N - 1}$ +$\textrm{Query}_0$ +$\textrm{Query}_1$ +: +$\textrm{Query}_{Q - 1}$ +~~~ + +{{example example_00}} diff --git a/datastructure/range_chmin_chmax_add_range_sum/verifier.cpp b/datastructure/range_chmin_chmax_add_range_sum/verifier.cpp new file mode 100644 index 000000000..93786ea8a --- /dev/null +++ b/datastructure/range_chmin_chmax_add_range_sum/verifier.cpp @@ -0,0 +1,51 @@ +#include +#include "testlib.h" +#include "params.h" +#include "segtree.hpp" + +int main() { + registerValidation(); + + int n = inf.readInt(1, N_AND_Q_MAX, "N"); + inf.readSpace(); + int q = inf.readInt(1, N_AND_Q_MAX, "Q"); + inf.readEoln(); + + std::vector init(n); + for (int i = 0; i < n; i++) { + long long a = inf.readLong(-A_ABS_MAX, A_ABS_MAX, "a_i"); + if (i != n - 1) inf.readSpace(); + init[i] = { a, a }; + } + inf.readEoln(); + chmin_chmax_add_min_max_segment_tree segtree(init.begin(), init.end()); + + for (int i = 0; i < q; i++) { + int t = inf.readInt(0, 3, "t"); + inf.readSpace(); + int l = inf.readInt(0, n - 1, "l"); + inf.readSpace(); + int r = inf.readInt(l + 1, n, "r"); + if (t == 0) { + inf.readSpace(); + long long b = inf.readLong(-2*A_ABS_MAX, 2*A_ABS_MAX, "b"); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { b, LLONG_MIN, 0ll }); + } else if (t == 1) { + inf.readSpace(); + long long b = inf.readLong(-2*A_ABS_MAX, 2*A_ABS_MAX, "b"); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, b, 0ll }); + } else if (t == 2) { + inf.readSpace(); + long long b = inf.readLong(-2*A_ABS_MAX, 2*A_ABS_MAX, "b"); + segtree.range_apply(l, r, (typename chmin_chmax_add_monoid::value_type) { LLONG_MAX, LLONG_MIN, b }); + } else { + // nop + } + auto a = segtree.range_get(0, n); + ensure(-A_ABS_MAX <= a.min); + ensure(a.max <= A_ABS_MAX); + inf.readEoln(); + } + inf.readEof(); + return 0; +} diff --git a/problems.toml b/problems.toml index 692851369..c184c4743 100644 --- a/problems.toml +++ b/problems.toml @@ -17,6 +17,9 @@ [problems.range_affine_range_sum] dir = 'datastructure/range_affine_range_sum' +[problems.range_chmin_chmax_add_range_sum] + dir = 'datastructure/range_chmin_chmax_add_range_sum' + [problems.vertex_add_path_sum] dir = 'datastructure/vertex_add_path_sum'