結果
問題 | No.235 めぐるはめぐる (5) |
ユーザー | noshi91 |
提出日時 | 2018-04-12 17:32:23 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 920 ms / 10,000 ms |
コード長 | 5,265 bytes |
コンパイル時間 | 601 ms |
コンパイル使用メモリ | 57,744 KB |
実行使用メモリ | 20,096 KB |
最終ジャッジ日時 | 2024-06-26 21:28:42 |
合計ジャッジ時間 | 4,615 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 920 ms
20,096 KB |
testcase_01 | AC | 450 ms
19,968 KB |
testcase_02 | AC | 881 ms
19,968 KB |
ソースコード
#define NDEBUG #define _CRT_SECURE_NO_WARNINGS #include <cassert> #include <utility> #include <vector> template <typename ValueMonoid, typename OperatorMonoid, class Modify> class LinkCutTree { public: using value_type = ValueMonoid; using operator_type = OperatorMonoid; private: struct node_t { node_t *left, *right, *par; value_type value, sum; operator_type lazy; bool isroot, reversed; node_t() : left(nullptr), right(nullptr), par(nullptr), value(), sum(), lazy(), isroot(1), reversed(0) {} bool isleft() const { return par->left == this; } void assign(const operator_type &data) { lazy = lazy + data; } void haulL(node_t *const t) { left = t; if (t) t->par = this; } void haulR(node_t *const t) { right = t; if (t) t->par = this; } }; value_type reflect(const node_t *const t) const { if (!t) return value_type(); if (t->reversed) return m(~t->sum, t->lazy); return m(t->sum, t->lazy); } void recalc(node_t *const t) { t->sum = reflect(t->left) + t->value + reflect(t->right); } void splay(node_t *const t) { node_t *p, *pp = t, *x = t->par; while (!t->isroot) { if (x->left == pp) x->left = t; else x->right = t; p = t->par; if (p->isroot) { t->par = p->par; std::swap(t->isroot, p->isroot); if (p->left == t) { p->haulL(t->right); t->haulR(p); } else { p->haulR(t->left); t->haulL(p); } recalc(p); break; } pp = p->par; x = pp->par; std::swap(t->isroot, pp->isroot); if (t->isleft()) { if (p->isleft()) { pp->haulL(p->right); p->haulR(pp); } else { pp->haulR(t->left); t->haulL(pp); } p->haulL(t->right); t->haulR(p); } else { if (p->isleft()) { pp->haulL(t->right); t->haulR(pp); } else { pp->haulR(p->left); p->haulL(pp); } p->haulR(t->left); t->haulL(p); } recalc(pp); recalc(p); t->par = x; } } void expose(node_t *const t, node_t *const prev) { splay(t); if (t->right) t->right->isroot = 1; t->right = prev; if (prev) prev->isroot = 0; recalc(t); if (t->par) expose(t->par, t); } void push(node_t *const t) { if (t->left) t->left->assign(t->lazy); if (t->right) t->right->assign(t->lazy); t->value = m(t->value, t->lazy); t->lazy = operator_type(); if (!t->reversed) return; std::swap(t->left, t->right); if (t->left) t->left->reversed ^= 1; if (t->right) t->right->reversed ^= 1; t->value = ~t->value; t->reversed = 0; } void propagate(node_t *const t) { if (t->par) propagate(t->par); push(t); } void expose(node_t *const n) { propagate(n); expose(n, nullptr); splay(n); recalc(n); } using container_type = std::vector<node_t>; public: using size_type = typename container_type::size_type; private: container_type tree; const Modify m; void reroot(const size_type v) { expose(&tree[v]); tree[v].reversed ^= 1; } public: explicit LinkCutTree(const size_type size, const Modify &m = Modify()) : tree(size), m(m) {} explicit LinkCutTree(const std::vector<value_type> &a, const Modify &m = Modify()) : tree(a.size()), m(m) { for (size_type i = 0; i < a.size(); ++i) tree[i].value = tree[i].sum = a[i]; } void link(const size_type child, const size_type parent) { assert(child < size()); assert(parent < size()); reroot(child); tree[child].par = &tree[parent]; } void cut(const size_type child) { assert(child < size()); node_t *const n = &tree[child]; expose(n); if (n->left) { n->left->isroot = 1; n->left->par = nullptr; } n->left = nullptr; n->sum = n->value; } void update(const size_type u, const size_type v, const operator_type &data) { assert(u < size()); assert(v < size()); reroot(u); expose(&tree[v]); tree[v].assign(data); } value_type path(const size_type u, const size_type v) { assert(u < size()); assert(v < size()); reroot(u); expose(&tree[v]); return tree[v].sum; } size_type size() const noexcept { return tree.size(); } bool empty() const noexcept { return tree.empty(); } }; #include<cstdint> using uint32 = std::uint_fast32_t; constexpr uint32 MOD = 1000000007; struct parade { uint32 z; parade(uint32 z = 0) :z(z) {} parade operator+(const parade &o)const { return parade((z + o.z) % MOD); } }; struct city { uint32 s, c; city(uint32 s = 0, uint32 c = 0) :s(s), c(c) {} city operator~()const { return *this; } city operator+(const city &o)const { return city((s + o.s) % MOD, (c + o.c) % MOD); } }; struct hoge { city operator()(const city &x, const parade &y)const { return city((static_cast<std::uint_fast64_t>(x.c)*y.z + x.s) % MOD, x.c); } }; #include<cstdio> #include<vector> int main(void) { int n; scanf("%d", &n); std::vector<city> d(n); for (auto &e : d)scanf("%u", &e.s); for (auto &e : d)scanf("%u", &e.c); LinkCutTree<city, parade, hoge> T(d); while (--n) { int a, b; scanf("%d %d", &a, &b); T.link(a - 1, b - 1); } int q; scanf("%d", &q); while (q--) { int t, x, y; parade z; scanf("%d %d %d", &t, &x, &y); --x, --y; if (t) { printf("%u\n", T.path(x, y).s); } else { scanf("%u", &z.z); T.update(x, y, z); } } return 0; }