diff --git a/data_structure/persistent_range_affine_range_sum/checker.cpp b/data_structure/persistent_range_affine_range_sum/checker.cpp new file mode 100644 index 00000000..6a66d533 --- /dev/null +++ b/data_structure/persistent_range_affine_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/data_structure/persistent_range_affine_range_sum/gen/example_00.in b/data_structure/persistent_range_affine_range_sum/gen/example_00.in new file mode 100644 index 00000000..672b729b --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/example_00.in @@ -0,0 +1,13 @@ +5 11 +1 2 3 4 5 +2 -1 0 5 +0 -1 2 4 100 1 +0 1 1 3 100 3 +2 2 1 5 +2 2 0 5 +1 2 -1 1 3 +2 5 0 1 +2 5 0 2 +2 5 0 3 +2 5 0 4 +2 5 0 5 diff --git a/data_structure/persistent_range_affine_range_sum/gen/example_01.in b/data_structure/persistent_range_affine_range_sum/gen/example_01.in new file mode 100644 index 00000000..7d24f7d5 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/example_01.in @@ -0,0 +1,12 @@ +10 10 +98571302 347764691 874908879 522525408 665451426 585614689 752625419 867933974 588349757 331245164 +2 -1 5 7 +1 -1 -1 8 9 +0 -1 3 4 559932567 67455332 +1 1 1 0 8 +1 3 1 5 9 +2 1 1 2 +1 2 -1 5 6 +0 -1 0 9 703344909 379527638 +2 6 2 9 +2 7 7 9 diff --git a/data_structure/persistent_range_affine_range_sum/gen/max_less_query_types.cpp b/data_structure/persistent_range_affine_range_sum/gen/max_less_query_types.cpp new file mode 100644 index 00000000..09fd2480 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/max_less_query_types.cpp @@ -0,0 +1,67 @@ +#include +#include "../params.h" +#include "random.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + vector query_freq; + switch(seed){ + case 0 : + query_freq = { 0 }; break; + case 1 : + query_freq = { 1 }; break; + case 2 : + query_freq = { 2 }; break; + case 3 : + query_freq = { 0,1 }; break; + case 4 : + query_freq = { 1,2 }; break; + case 5 : + query_freq = { 0,2 }; break; + default : + return 0; + } + + int n = N_MAX; + int q = Q_MAX; + printf("%d %d\n", n, q); + for (int i = 0; i < n; i++) { + int a = gen.uniform(0, MOD - 1); + printf("%d", a); + if (i != n - 1) printf(" "); + } + printf("\n"); + + std::vector data_enable; + data_enable.push_back(-1); + auto choose_data = [&]() -> int { + int i = gen.uniform(0, (int)data_enable.size() - 1); + return data_enable[i]; + }; + + for (int i = 0; i < q; i++) { + int t = query_freq[gen.uniform(0, (int)query_freq.size()-1)]; + int k = choose_data(); + printf("%d %d ", t, k); + if (t == 0) { + auto [l, r] = gen.uniform_pair(0, n); + int b = gen.uniform(1, MOD - 1); + int c = gen.uniform(0, MOD - 1); + printf("%d %d %d %d\n", l, r, b, c); + data_enable.push_back(i); + } else if(t == 1) { + int s = choose_data(); + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d %d\n", s, l, r); + data_enable.push_back(i); + } else { + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d\n", l, r); + } + } + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/gen/max_random.cpp b/data_structure/persistent_range_affine_range_sum/gen/max_random.cpp new file mode 100644 index 00000000..ad1d11b4 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/max_random.cpp @@ -0,0 +1,49 @@ +#include +#include "../params.h" +#include "random.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + int q = Q_MAX; + printf("%d %d\n", n, q); + for (int i = 0; i < n; i++) { + int a = gen.uniform(0, MOD - 1); + printf("%d", a); + if (i != n - 1) printf(" "); + } + printf("\n"); + + std::vector data_enable; + data_enable.push_back(-1); + auto choose_data = [&]() -> int { + int i = gen.uniform(0, (int)data_enable.size() - 1); + return data_enable[i]; + }; + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 2); + int k = choose_data(); + printf("%d %d ", t, k); + if (t == 0) { + auto [l, r] = gen.uniform_pair(0, n); + int b = gen.uniform(1, MOD - 1); + int c = gen.uniform(0, MOD - 1); + printf("%d %d %d %d\n", l, r, b, c); + data_enable.push_back(i); + } else if(t == 1) { + int s = choose_data(); + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d %d\n", s, l, r); + data_enable.push_back(i); + } else { + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d\n", l, r); + } + } + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/gen/random.cpp b/data_structure/persistent_range_affine_range_sum/gen/random.cpp new file mode 100644 index 00000000..55071797 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/random.cpp @@ -0,0 +1,47 @@ +#include "random.h" +#include +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(N_MIN, N_MAX); + int q = gen.uniform(Q_MIN, Q_MAX); + printf("%d %d\n", n, q); + for (int i = 0; i < n; i++) { + int a = gen.uniform(0, MOD - 1); + printf("%d", a); + if (i != n - 1) printf(" "); + } + printf("\n"); + + std::vector data_enable; + data_enable.push_back(-1); + auto choose_data = [&]() -> int { + int i = gen.uniform(0, (int)data_enable.size() - 1); + return data_enable[i]; + }; + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 2); + int k = choose_data(); + printf("%d %d ", t, k); + if (t == 0) { + auto [l, r] = gen.uniform_pair(0, n); + int b = gen.uniform(1, MOD - 1); + int c = gen.uniform(0, MOD - 1); + printf("%d %d %d %d\n", l, r, b, c); + } else if(t == 1) { + int s = choose_data(); + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d %d\n", s, l, r); + } else { + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d\n", l, r); + } + } + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/gen/small.cpp b/data_structure/persistent_range_affine_range_sum/gen/small.cpp new file mode 100644 index 00000000..f8c43c66 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/small.cpp @@ -0,0 +1,49 @@ +#include "random.h" +#include +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = seed % 10 + N_MIN; + int q = 1000; + printf("%d %d\n", n, q); + for (int i = 0; i < n; i++) { + int a = gen.uniform(0, MOD - 1); + printf("%d", a); + if (i != n - 1) printf(" "); + } + printf("\n"); + + std::vector data_enable; + data_enable.push_back(-1); + auto choose_data = [&]() -> int { + int i = gen.uniform(0, (int)data_enable.size() - 1); + return data_enable[i]; + }; + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 2); + int k = choose_data(); + printf("%d %d ", t, k); + if (t == 0) { + auto [l, r] = gen.uniform_pair(0, n); + int b = gen.uniform(1, MOD - 1); + int c = gen.uniform(0, MOD - 1); + printf("%d %d %d %d\n", l, r, b, c); + data_enable.push_back(i); + } else if(t == 1) { + int s = choose_data(); + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d %d\n", s, l, r); + data_enable.push_back(i); + } else { + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d\n", l, r); + } + } + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/gen/small_random.cpp b/data_structure/persistent_range_affine_range_sum/gen/small_random.cpp new file mode 100644 index 00000000..a4bb3303 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/gen/small_random.cpp @@ -0,0 +1,49 @@ +#include "random.h" +#include +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(N_MIN, 2000); + int q = gen.uniform(Q_MIN, 2000); + printf("%d %d\n", n, q); + for (int i = 0; i < n; i++) { + int a = gen.uniform(0, MOD - 1); + printf("%d", a); + if (i != n - 1) printf(" "); + } + printf("\n"); + + std::vector data_enable; + data_enable.push_back(-1); + auto choose_data = [&]() -> int { + int i = gen.uniform(0, (int)data_enable.size() - 1); + return data_enable[i]; + }; + + for (int i = 0; i < q; i++) { + int t = gen.uniform(0, 2); + int k = choose_data(); + printf("%d %d ", t, k); + if (t == 0) { + auto [l, r] = gen.uniform_pair(0, n); + int b = gen.uniform(1, MOD - 1); + int c = gen.uniform(0, MOD - 1); + printf("%d %d %d %d\n", l, r, b, c); + data_enable.push_back(i); + } else if(t == 1) { + int s = choose_data(); + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d %d\n", s, l, r); + data_enable.push_back(i); + } else { + auto [l, r] = gen.uniform_pair(0, n); + printf("%d %d\n", l, r); + } + } + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/hash.json b/data_structure/persistent_range_affine_range_sum/hash.json new file mode 100644 index 00000000..3ed76315 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/hash.json @@ -0,0 +1,54 @@ +{ + "example_00.in": "880029df1447bcc170d9a3bf87d94e49f93e610cd5031559b29471ae237ffdb9", + "example_00.out": "be42d374928db1abecf5c478f9c4958718f6ee27d0a8d4a52578f23e9a527f3b", + "example_01.in": "9e8f63724e79805ac5645816b1cf1671a52f8c1692314a42db857fd97d0e7c1d", + "example_01.out": "073e3decf6ae6f7fe43b3bf2c93ba5f2582c5d6861ace0ecec2220020e77671c", + "max_less_query_types_00.in": "1bb612d962e35ca0b350b63437db7e2ccd813415c25394c6e50e5ef46a51b458", + "max_less_query_types_00.out": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "max_less_query_types_01.in": "8696e08de296e3604c5cbd307555bee527547bf78540d5b44f684f75abee95df", + "max_less_query_types_01.out": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "max_less_query_types_02.in": "f78de41f677a73e71b68dc7dc65f43170c0d49a8e1de8b2d46aecdcbb96421fb", + "max_less_query_types_02.out": "4f878ce6fb424c1e5c761fb7a4c41a1078087465b21312b82ef38844092a27b3", + "max_less_query_types_03.in": "1a83ec6d5793b65ae1cb9dbf31bdedc4cbb1a61e5ad577f9b291ffdd0e143299", + "max_less_query_types_03.out": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "max_less_query_types_04.in": "064d440cf51a261cdd260b283770b8428d72ce749c71dbe3140fe1466de5cd2f", + "max_less_query_types_04.out": "2e643ee061a5e6ec781e1598e776f1c2eaa0b2807ccc91e01413bbb51cd0739f", + "max_less_query_types_05.in": "a5857db1eba06d86d3c89af15ad9e692971ee3fd9e751752718c33b8e85fbc14", + "max_less_query_types_05.out": "9bb0b939a90b6a3c0260e0682a98f297fccb8006f79c32c2367c3293865747e6", + "max_random_00.in": "a3f772b64259887bdb0e693aafbf036ce6d3eeec2677bcab141f17e57e2c974e", + "max_random_00.out": "643f4dcc8b6dc3dbf07950155eca4846324c0d1fd45776274d53a15ca94ba48d", + "max_random_01.in": "25d9ac2f08b8f53cec42ed7b37a18a4f450ea5e90cdf57b2dd909d56a39fe347", + "max_random_01.out": "0b68e5d447d109ec31ab68b4bac24e997d38b0dc5239996bb514923d367fac87", + "max_random_02.in": "013581017f26c236d6eb9b0d9526cffb16e35b7afc50bd95515d5d00b095fb20", + "max_random_02.out": "42ded9baf54102f1a7ffc7c3179a9f26c475780c65ce032bdb3ed9471bd4cd68", + "random_00.in": "fe851bcd1922c6822ba1945d92256b46c0156f873e63efcf5dafd742046c0b9d", + "random_00.out": "7be4dc3ba07c003875fbe7e4c8c0eac678b87acc71c3c597a8a4b65db172fd55", + "random_01.in": "85b8597d51b67139211552523bcbd6966f41ef2995166195b9f25c545e23f4e5", + "random_01.out": "39214aaffdf99a6bfc888ba63a9dc1bd453ba7d17cb6c456f934f52dbd131ae0", + "random_02.in": "7167a1d5e229952b427cabe63bfd569de986e3da852b89a7f7322df2405e4273", + "random_02.out": "162052f21f43757707d70a4e4480e22ef7ff8ca8039ff84ec086185bfd4b6249", + "small_00.in": "a7442fd645065311c90b9799161d468e9438407f261c3fe9bfb9f952fb41a0fc", + "small_00.out": "8991954d2275cf45f1627612238f5fe3f8454b07db82642b048b5fede8164c2a", + "small_01.in": "21d79bb75833024156d49dd8a1a7f9c6ab6e7db8b47e5069039f8ff9d7767a7b", + "small_01.out": "334ebea3924ffc1a0ebc83951a9910790e3529d988bab79bc3c666ab1d848faa", + "small_02.in": "48b742a8ee580cebd6739e040373ff50e2f7dccbfd10d27dce453637dba45fa2", + "small_02.out": "b8b1f3b55437259a5327e960d7278bf32aaa25b766c00aa05836bf3c72641ec9", + "small_03.in": "05a901d1750083fc3dfc93a7fe1b112849d2199a203e36d0e38a5170610f8b92", + "small_03.out": "a1e478d57ba1dd590ab5dbc0d102b9e6164a6cce5b8a70edf52357d1df5f9be1", + "small_04.in": "e25211c5173f5452f1669aa6489cc8f9e7bb64e4eeb05c83d5e373d548d9fcb2", + "small_04.out": "362c914504ff83248939b5bd68b3ba5226863414ffc290cd845f05e12cdf3143", + "small_05.in": "1d602c2e72b2b1b67d85eccb03e5106871d10396e3c91e26777fbf614cbcd788", + "small_05.out": "e95363434cab5da34c385a96622cd5fd216610b12885534cc81410d314a425c8", + "small_06.in": "4d00b3106e6db6f1de2f7c365eaacfe45f097b6dd454ff4cdb092e44845ddab9", + "small_06.out": "724043682c37e8613f812cb723ee151b8f914f0888b84a4d2c28ad7c35913033", + "small_07.in": "a8bb20468e37a94ff845ae84e3068f570a5fa31f46696bebb82dbf406ee89f1d", + "small_07.out": "b39cf3e5c0f982c4eca6df18a2c0f7a0c0b2f9c354944a3a29917b2daff41600", + "small_08.in": "5727545c2965c0dc840e81b79253b388f2f53371bee3ae15a8cb604916e371fd", + "small_08.out": "c56f7d4b69e1e380772e00eea93755a80bf616dec21ef8c30d859736d407b499", + "small_09.in": "2d5bec5c8dad3b3adfa4834fb2e9e29fac9688959281ddaf1f2471ddfabb5a36", + "small_09.out": "2e8232c93ae93474ace27fadaa0c63427270ea4155474a353c23a0efccc0e6be", + "small_random_00.in": "665b27e75648b446a1f238aab0a87c5a5a8aec5909e6478c8c8175aabd237958", + "small_random_00.out": "1c9f3064e279d38d71d59d7b1bd47cfbb870aa49d146f8dd9272fad027e7ef41", + "small_random_01.in": "4e179ab49fa946ccdf55129fbe39abdb6821593f294cfb6e2ea62c7253e64f51", + "small_random_01.out": "d450a333f23d8290ecbbba291f8179493a7086618d09b6af463c7f4ae443f247" +} \ No newline at end of file diff --git a/data_structure/persistent_range_affine_range_sum/info.toml b/data_structure/persistent_range_affine_range_sum/info.toml new file mode 100644 index 00000000..82f92fb6 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/info.toml @@ -0,0 +1,29 @@ +title = 'Persistent Range Affine Range Sum' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/760" + +[[tests]] + name = "example.in" + number = 2 +[[tests]] + name = "max_less_query_types.cpp" + number = 6 +[[tests]] + name = "max_random.cpp" + number = 3 +[[tests]] + name = "random.cpp" + number = 3 +[[tests]] + name = "small_random.cpp" + number = 2 +[[tests]] + name = "small.cpp" + number = 10 + +[params] + N_MIN = 1 + Q_MIN = 1 + N_MAX = 100000 + Q_MAX = 100000 + MOD = 998244353 diff --git a/data_structure/persistent_range_affine_range_sum/sol/correct.cpp b/data_structure/persistent_range_affine_range_sum/sol/correct.cpp new file mode 100644 index 00000000..1beff1cc --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/sol/correct.cpp @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include + +#include + +#include +namespace nachia{ + +// ax + by = gcd(a,b) +// return ( x, - ) +std::pair ExtGcd(long long a, long long b){ + long long x = 1, y = 0; + while(b){ + long long u = a / b; + std::swap(a-=b*u, b); + std::swap(x-=y*u, y); + } + return std::make_pair(x, a); +} + +} // namespace nachia + +namespace nachia{ + +template +struct StaticModint{ +private: + using u64 = unsigned long long; + unsigned int x; +public: + + using my_type = StaticModint; + template< class Elem > + static Elem safe_mod(Elem x){ + if(x < 0){ + if(0 <= x+MOD) return x + MOD; + return MOD - ((-(x+MOD)-1) % MOD + 1); + } + return x % MOD; + } + + StaticModint() : x(0){} + StaticModint(const my_type& a) : x(a.x){} + StaticModint& operator=(const my_type&) = default; + template< class Elem > + StaticModint(Elem v) : x(safe_mod(v)){} + unsigned int operator*() const noexcept { return x; } + my_type& operator+=(const my_type& r) noexcept { auto t = x + r.x; if(t >= MOD) t -= MOD; x = t; return *this; } + my_type operator+(const my_type& r) const noexcept { my_type res = *this; return res += r; } + my_type& operator-=(const my_type& r) noexcept { auto t = x + MOD - r.x; if(t >= MOD) t -= MOD; x = t; return *this; } + my_type operator-(const my_type& r) const noexcept { my_type res = *this; return res -= r; } + my_type operator-() const noexcept { my_type res = *this; res.x = ((res.x == 0) ? 0 : (MOD - res.x)); return res; } + my_type& operator*=(const my_type& r)noexcept { x = (u64)x * r.x % MOD; return *this; } + my_type operator*(const my_type& r) const noexcept { my_type res = *this; return res *= r; } + my_type pow(unsigned long long i) const noexcept { + my_type a = *this, res = 1; + while(i){ if(i & 1){ res *= a; } a *= a; i >>= 1; } + return res; + } + my_type inv() const { return my_type(ExtGcd(x, MOD).first); } + unsigned int val() const noexcept { return x; } + static constexpr unsigned int mod() { return MOD; } + static my_type raw(unsigned int val) noexcept { auto res = my_type(); res.x = val; return res; } + my_type& operator/=(const my_type& r){ return operator*=(r.inv()); } + my_type operator/(const my_type& r) const { return operator*(r.inv()); } +}; + +} // namespace nachia + +namespace nachia { + +template< + class S, + class F, + S op(S l, S r), + F composition(F f, F x), + S mapping(F f, S x) +> +struct PersistentLazySegtree { +public: + struct Node { + int l; + int r; + S a; + F f; + }; + struct Agent{ + public: + Agent(){} + Agent(int _sz, int _root, PersistentLazySegtree* _q) : sz(_sz), root(_root), q(_q) {} + int size() const { return sz; } + Agent set(int at, S x) const { return copy(q->set(root,sz,at,x,q->id)); } + S prod(int l, int r) const { return q->prod(root,sz,l,r,q->id); } + Agent apply(int l, int r, F f) const { return copy(q->apply(root,sz,l,r,f,q->id)); } + Agent crossover(Agent right, int p) const { + return copy(q->crossover(root, right.root, sz, p, q->id, q->id)); + } + private: + int sz; + int root; + PersistentLazySegtree* q = nullptr; + Agent copy(int newRoot) const { return Agent(sz, newRoot, q); } + }; + + PersistentLazySegtree(){} + + PersistentLazySegtree(S _e, F _id, int reserved_size = 0) + : e(_e), id(_id) { v.reserve(reserved_size); } + + Agent construct(const std::vector& val){ + return { int(val.size()), fromRange(val.begin(), int(val.size())), this }; + } + +private: + int newLeaf(S x){ + int res = v.size(); + v.push_back({ -1, -1, x, id }); + return res; + } + int newMid(int l, int r){ + int res = v.size(); + v.push_back({ l, r, op(v[l].a, v[r].a), id }); + return res; + } + int applyAtNode(int p, F f){ + if(v[p].l == -1) return newLeaf(mapping(f, v[p].a)); + int res = v.size(); + v.push_back({ v[p].l, v[p].r, mapping(f, v[p].a), composition(f, v[p].f) }); + return res; + } + int set(int p, int n, int at, S x, F prop){ + if(n == 1) return newLeaf(x); + int m = n / 2; + auto nxf = composition(prop, v[p].f); + if(at < m) return newMid(set(v[p].l, m, at, x, nxf), applyAtNode(v[p].r, nxf)); + return newMid(applyAtNode(v[p].l, nxf), set(v[p].r, n-m, at-m, x, nxf)); + } + S prod(int p, int n, int l, int r, F prop){ + if(l <= 0 && n <= r) return mapping(prop, v[p].a); + if(r <= 0 || n <= l) return e; + int m = n / 2; + auto nxf = composition(prop, v[p].f); + return op( + prod(v[p].l, m, l, r, nxf), + prod(v[p].r, n-m, l-m, r-m, nxf) + ); + } + int apply(int p, int n, int l, int r, F f, F prop){ + if(l <= 0 && n <= r) return applyAtNode(p, composition(f, prop)); + if(r <= 0 || n <= l) return applyAtNode(p, prop); + int m = n / 2; + auto nxf = composition(prop, v[p].f); + int l2 = apply(v[p].l, m, l, r, f, nxf); + int r2 = apply(v[p].r, n-m, l-m, r-m, f, nxf); + return newMid(l2, r2); + } + int crossover(int p, int q, int n, int at, F propl, F propr){ + if(at <= 0) return applyAtNode(q, propr); + if(n <= at) return applyAtNode(p, propl); + int m = n / 2; + auto nxfl = composition(propl, v[p].f); + auto nxfr = composition(propr, v[q].f); + int l2 = crossover(v[p].l, v[q].l, m, at, nxfl, nxfr); + int r2 = crossover(v[p].r, v[q].r, n-m, at-m, nxfl, nxfr); + return newMid(l2, r2); + } + int fromRange(typename std::vector::const_iterator a, int n){ + if(n == 1) return newLeaf(a[0]); + int m = n / 2; + return newMid(fromRange(a, m), fromRange(a+m, n-m)); + } + + S e; + F id; + std::vector v; +}; + +} // namespace nachia + +template +struct ValArrayOverRing { + using X = ValArrayOverRing; + std::array m; + T& operator[](int i){ return m[i]; } + const T& operator[](int i) const { return m[i]; } + X& operator+=(const X& r){ for(int i=0; i +struct Affine{ + using X = ValArrayOverRing; + Value a; + Value b; + static Affine Id(){ return { Value(1), Value(0) }; } + Affine operator()(const Affine& x) const { return { a * x.a, a * x.b + b }; } + X operator()(const X& x) const { return { x[0], a * x[1] + b * x[0] }; } + Affine operator+(const Affine& r) const { return { a + r.a, b + r.b }; } + Affine operator-(const Affine& r) const { return { a - r.a, b - r.b }; } + Affine& operator+=(const Affine& r) const { a += r.a; b += r.b; return *this; } + Affine& operator-=(const Affine& r) const { a -= r.a; b -= r.b; return *this; } +}; + +} // namespace nachia + + +using namespace std; + +using Modint = nachia::StaticModint<998244353>; +using Affine = nachia::Affine; +using Value = Affine::X; +Value op(Value l, Value r){ return l + r; } +Value mapping(Affine f, Value x){ return f(x); } +Affine composition(Affine f, Affine x){ return f(x); } + +vector solve(int N, int Q, const vector& A, const vector>& queries){ + using Ds = nachia::PersistentLazySegtree; + Ds ds(Value(), Affine::Id()); + vector data(Q+1); + vector mA(N); + for(int i=0; i ans; + for(int qi=1; qi<=Q; qi++){ + auto& q = queries[qi-1]; + if(q[0] == 0){ + auto [dum0, t, l, r, c, d] = q; t++; + Modint cm = c; + Modint dm = d; + data[qi] = data[t].apply(l, r, {cm,dm}); + } + else if(q[0] == 1){ + auto [dum0, t, s, l, r, dum1] = q; t++; s++; + data[qi] = data[t].crossover(data[s], l).crossover(data[t], r); + } + else if(q[0] == 2){ + auto [dum0, t, l, r, dum1, dum2] = q; t++; + Modint v = data[t].prod(l, r)[1]; + ans.push_back(int(v.val())); + } + } + return ans; +} + + +int main(){ + int N, Q; scanf("%d%d", &N, &Q); + vector A(N); + for(auto& a : A) scanf("%d", &a); + vector> queries(Q); + for(auto& q : queries){ + scanf("%d", &q[0]); + if(q[0] == 0){ + scanf("%d%d%d%d%d", &q[1], &q[2], &q[3], &q[4], &q[5]); + } else if(q[0] == 1){ + scanf("%d%d%d%d", &q[1], &q[2], &q[3], &q[4]); + q[5] = 0; + } else if(q[0] == 2){ + scanf("%d%d%d", &q[1], &q[2], &q[3]); + q[4] = q[5] = 0; + } else exit(1); + } + auto ans = solve(N, Q, A, queries); + for(auto a : ans) printf("%d\n", a); + return 0; +} diff --git a/data_structure/persistent_range_affine_range_sum/task.md b/data_structure/persistent_range_affine_range_sum/task.md new file mode 100644 index 00000000..ff4e35ba --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/task.md @@ -0,0 +1,66 @@ +## @{keyword.statement} + +@{lang.en} +Given a size $N$ interger sequence $a _ 0, a _ 1, \dots, a _ {N - 1}$. +Let $A _ {-1}$ be the sequence $(a _ 0, a _ 1, \dots, a _ {N - 1})$. + +For $i=0,1,\ldots ,Q-1$ , process a query as follows: + +- `0 $k$ $l$ $r$ $b$ $c$`: Make a copy of $A _ {k}$ as $A _ i$ . For each $j = l, l+1, \dots, {r - 1}$ , on $A _ i$ , $a _ j \gets b \times a _ j + c$. +- `1 $k$ $s$ $l$ $r$`: Make a copy of $A _ {k}$ as $A _ i$ . For each $j = l, l+1, \dots, {r - 1}$ , on $A _ i$ , $a _ j \gets a ^ {\prime} _ j$ (where $a ^ {\prime} _ j$ is the value of $a _ j$ in $A _ {s}$ ). +- `2 $k$ $l$ $r$`: Print $\sum_{j = l} ^ {r - 1} a _ j \bmod @{param.MOD}$ from $A _ {k}$. +@{lang.ja} +長さ $N$ の整数列 $a_0, a_1, \dots, a_{N - 1}$ が与えられます。 +$A _ {-1}$ を数列 $(a _ 0, a _ 1, \dots, a _ {N - 1})$ とします. + +$i=0,1,\ldots ,Q-1$ についてクエリを処理してください。 + +- `0 $k$ $l$ $r$ $b$ $c$`: $A _ {k}$ を複製して $A _ i$ とします。 $A _ i$ において、 各 $j = l, l+1, \dots, {r - 1}$ について、$a _ j \gets b \times a _ j + c$ 。 +- `1 $k$ $s$ $l$ $r$`: $A _ {k}$ を複製して $A _ i$ とします。 $A _ i$ において、 各 $j = l, l+1, \dots, {r - 1}$ について、$a _ j \gets a ^ {\prime} _ j$ (ここで、 $a ^ {\prime} _ j$ は $A _ {s}$ における $a _ j$ とする) 。 +- `2 $k$ $l$ $r$`: $A _ {k}$ における $\sum_{j = l} ^ {r - 1} a _ j \bmod @{param.MOD}$ を出力してください。 +@{lang.end} + +## @{keyword.constraints} + +@{lang.en} +Let $t _ i$ as the type of the $i$-th query ($0\leq i \lt Q$ , $t _ i\in\lbrace 0,1,2\rbrace$) . + +- $1 \leq N \leq @{param.N_MAX}$ +- $1 \leq Q \leq @{param.Q_MAX}$ +- $0 \leq a \lt @{param.MOD}$ +- $1 \leq b \lt @{param.MOD}$ +- $0 \leq c \lt @{param.MOD}$ +- $-1 \leq k \lt i$ +- $k=-1$ or $t _ k\in \lbrace 0,1\rbrace$ +- $-1 \leq s \lt i$ +- $s=-1$ or $t _ s\in \lbrace 0,1\rbrace$ +- $0 \leq l \lt r \leq N$ +@{lang.ja} +$t _ i$ を、 $i$ 番目のクエリの種類とします ($0\leq i \lt Q$ , $t _ i\in\lbrace 0,1,2\rbrace$)。 + +- $1 \leq N \leq @{param.N_MAX}$ +- $1 \leq Q \leq @{param.Q_MAX}$ +- $0 \leq a \lt @{param.MOD}$ +- $1 \leq b \lt @{param.MOD}$ +- $0 \leq c \lt @{param.MOD}$ +- $-1 \leq k \lt i$ +- $k=-1$ または $t _ k\in \lbrace 0,1\rbrace$ +- $-1 \leq s \lt i$ +- $s=-1$ または $t _ s\in \lbrace 0,1\rbrace$ +- $0 \leq l \lt r \leq N$ +@{lang.end} + +## @{keyword.input} + +~~~ +$N$ $Q$ +$a _ 0$ $a _ 1$ ... $a _ {N - 1}$ +$\textrm{Query}_0$ +$\textrm{Query}_1$ +: +$\textrm{Query}_{Q - 1}$ +~~~ + +@{example.example_00} + +@{example.example_01} diff --git a/data_structure/persistent_range_affine_range_sum/verifier.cpp b/data_structure/persistent_range_affine_range_sum/verifier.cpp new file mode 100644 index 00000000..4b837d69 --- /dev/null +++ b/data_structure/persistent_range_affine_range_sum/verifier.cpp @@ -0,0 +1,57 @@ +#include "testlib.h" +#include "params.h" + +int main() { + registerValidation(); + + int n = inf.readInt(N_MIN, N_MAX, "N"); + inf.readSpace(); + int q = inf.readInt(Q_MIN, Q_MAX, "Q"); + inf.readChar('\n'); + + for (int i = 0; i < n; i++) { + inf.readInt(0, MOD - 1, "a_i"); + if (i != n - 1) inf.readSpace(); + } + inf.readChar('\n'); + + // index +1 + std::vector has_data(q + 1, 0); + has_data[0] = 1; + + for (int i = 0; i < q; i++) { + int t = inf.readInt(0, 2, "t"); + inf.readSpace(); + int k = inf.readInt(-1, i - 1, "k"); + inf.readSpace(); + ensuref(has_data[k + 1] == 1, "the value of k is invalid"); + if (t == 0) { + int l = inf.readInt(0, n - 1, "l"); + inf.readSpace(); + int r = inf.readInt(0, n, "r"); + inf.readSpace(); + inf.readInt(1, MOD - 1, "b"); + inf.readSpace(); + inf.readInt(0, MOD - 1, "c"); + ensure(l < r); + has_data[i + 1] = 1; + } else if(t == 1) { + int s = inf.readInt(-1, i - 1, "s"); + inf.readSpace(); + int l = inf.readInt(0, n - 1, "l"); + inf.readSpace(); + int r = inf.readInt(0, n, "r"); + ensure(l < r); + ensuref(has_data[s + 1] == 1, "the value of s is invalid"); + has_data[i + 1] = 1; + } else if(t == 2) { + int l = inf.readInt(0, n - 1, "l"); + inf.readSpace(); + int r = inf.readInt(0, n, "r"); + ensure(l < r); + } + inf.readChar('\n'); + } + inf.readEof(); + return 0; +}