1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| #include <cstdio> #include <vector> #include <algorithm> struct Node { long long value, delta; Node *left, *right; int l, r; Node() { left = right = nullptr; l = r = delta = value = 0; } ~Node() { if (left) { delete left; delete right; } } } *root; std::vector<int> adj[100010]; int heavy[100010], size[100010], father[100010], top[100010], depth[100010]; int new_index[100010]; long long original_value[100010], indexed_value[100010]; int maxtop, n, m; long long kMod; void Dfs1(const int &cur, const int &fathernode) { father[cur] = fathernode, depth[cur] = depth[fathernode] + 1, size[cur] = 1; for (auto i : adj[cur]) { if (i != fathernode) { Dfs1(i, cur), size[cur] += size[i]; if (size[i] > size[heavy[cur]]) heavy[cur] = i; } } } void Dfs2(const int &cur, const int &topnode) { static int index_count(0); new_index[cur] = ++index_count, indexed_value[index_count] = original_value[cur]; top[cur] = topnode; if (heavy[cur]) { Dfs2(heavy[cur], topnode); for (auto i : adj[cur]) { if (i != father[cur] && i != heavy[cur]) { Dfs2(i, i); } } } } #define PUSH_UP(cur) cur->value = cur->left->value + cur->right->value; void Build(Node *cur, const int &l, const int &r) { if (l == r) { cur->value = indexed_value[l]; cur->l = cur->r = l; } else { cur->left = new Node, cur->right = new Node; register int mid((l + r) >> 1); cur->l = l, cur->r = r; Build(cur->left, l, mid), Build(cur->right, mid + 1, r); PUSH_UP(cur); } } #define PUSH_DOWN(cur) if (cur->delta) {cur->left->value = (cur->left->value + cur->delta * (cur->left->r - cur->left->l + 1)) % kMod, cur->right->value = (cur->right->value + cur->delta * (cur->right->r - cur->right->l + 1)) % kMod, cur->left->delta = (cur->left->delta + cur->delta) % kMod, cur->right->delta = (cur->right->delta + cur->delta) % kMod, cur->delta = 0;} void Modify(Node *cur, const int &l, const int &r, const long long &kDelta) { if (l <= cur->l && cur->r <= r) { cur->value += kDelta* ((cur->r - cur->l) + 1), cur->delta += kDelta; } else { PUSH_DOWN(cur); register int mid((cur->l + cur->r) >> 1); if (l <= mid) Modify(cur->left, l, r, kDelta); if (mid < r) Modify(cur->right, l, r, kDelta); PUSH_UP(cur); } } long long GetSum(Node *cur, const int &l, const int &r) { if (l <= cur->l && cur->r <= r) { return cur->value; } else { PUSH_DOWN(cur); register long long ret(0); register int mid((cur->l + cur->r) >> 1); if (l <= mid) (ret += GetSum(cur->left, l, r)) %= kMod; if (mid < r) (ret += GetSum(cur->right, l, r)) %= kMod; return ret % kMod; } } inline void PathModify(const int &x, const int &y, const long long &kDelta) { register int a(x), b(y); while (top[a] != top[b]) { if (depth[top[a]] < depth[top[b]]) std::swap(a, b); Modify(root, new_index[top[a]], new_index[a], kDelta); a = father[top[a]]; } if (depth[a] > depth[b]) std::swap(a, b); Modify(root, new_index[a], new_index[b], kDelta); } inline long long PathGetSum(const int &x, const int &y) { register int a(x), b(y); register long long ret(0ll); while (top[a] != top[b]) { if (depth[top[a]] < depth[top[b]]) std::swap(a, b); (ret += GetSum(root, new_index[top[a]], new_index[a])) %= kMod; a = father[top[a]]; } if (depth[a] > depth[b]) std::swap(a, b); return (ret + GetSum(root, new_index[a], new_index[b])) % kMod; } inline void SubTreeModify(const int &x, const long long &kDelta) { Modify(root, new_index[x], new_index[x] + size[x] - 1, kDelta); } inline long long SubTreeGetSum(const int &x) { return GetSum(root, new_index[x], new_index[x] + size[x] - 1); } int main(int argc, char const *argv[]) { scanf("%d %d %d %lld", &n, &m, &maxtop, &kMod); for (int i(1); i <= n; ++i) scanf("%lld", &original_value[i]); for (int i(1), u, v; i < n; ++i) { scanf("%d %d", &u, &v), adj[u].push_back(v), adj[v].push_back(u); } Dfs1(maxtop, maxtop), Dfs2(maxtop, maxtop), root = new Node, Build(root, 1, n); long long z; register int opt, x, y; while (m--) { scanf("%d", &opt); switch (opt) { case 1: { scanf("%d %d %lld", &x, &y, &z), PathModify(x, y, z % kMod); break; } case 2: { scanf("%d %d", &x, &y), printf("%lld\n", PathGetSum(x, y)); break; } case 3: { scanf("%d %lld", &x, &z), SubTreeModify(x, z % kMod); break; } case 4: { scanf("%d", &x), printf("%lld\n", SubTreeGetSum(x)); break; } } } return 0; }
|