#include using namespace std; struct N { int c[3]; unsigned l; int key; int cnt; int sign; int sign_sum; int above; int above_add; long long above_sum; N() : N(0) {} N(int k) : c{0, 0}, l(rand()), key(k), cnt(0), sign(0), sign_sum(0), above(0), above_add(0), above_sum(0ll) {} }; constexpr int kMaxDepth = 100; vector nodes(2); void Reserve(int cnt) { int cap = nodes.capacity(); while (cap - nodes.size() < cnt) cap *= 2; nodes.reserve(cap); } template int New(Args&& ...args) { nodes.emplace_back(forward(args)...); return nodes.size() - 1; } N& Get(int x) { return nodes[x]; } int& C(int x, int y) { return Get(x).c[y]; } int& P(int x) { return C(x, 2); } int Cpy(int o) { return o; } int Touch(int v) { if (!v) return v; C(v, 0) = Cpy(C(v, 0)); C(v, 1) = Cpy(C(v, 1)); N& n = Get(v); if (n.above_add) { for (int i = 0; i < 2; i++) { if (n.c[i]) { N& l = Get(n.c[i]); l.above_add += n.above_add; if (l.sign == 1) l.above += n.above_add; l.above_sum += (long long) n.above_add * l.cnt; } } n.above_add = 0; } return v; } int& TC(int& x) { return x = Touch(Cpy(x)); } int Update(int v) { if (!v) return v; N& n = Get(v); n.cnt = (n.sign == 1); n.sign_sum = n.sign; n.above_sum = n.above; if (n.c[0]) { N& l = Get(n.c[0]); n.cnt += l.cnt; n.sign_sum += l.sign_sum; n.above_sum += l.above_sum; } if (n.c[1]) { N& r = Get(n.c[1]); n.cnt += r.cnt; n.sign_sum += r.sign_sum; n.above_sum += r.above_sum; } return v; } int Merge(int a, int b, int c, int A = 1) { if (!TC(c)) return b ? Merge(a, 0, b) : Touch(a); if (!TC(a)) swap(a, b); if (A) Reserve(kMaxDepth * 2); TC(b); int p = A, x = 1, y; while (a) { if ((y = Get(a).l < Get(c).l)) swap(a, c); if (b and Get(a).l < Get(b).l) { if (x == y) swap(a, c); C(b, 0) = Merge(a, 0, C(b, 0), 0); C(b, 1) = Merge(C(b, 1), 0, c, 0); c = Update(b); break; } P(a) = p; p = C(p, x) = a; if (!Touch(a = C(p, x ^= y))) swap(a, b); } C(p, x) = c; while (p > 1) p = P(Update(p)); return C(A, 1); } template void Split(int v, int& L, int& M, int& R, const F& f, int A = 0, int B = 0) { if (!A) Reserve(kMaxDepth * 2); int a = A, b = A, x = 1, y; v = Cpy(v); C(A, 0) = C(A, 1) = 0; while (Touch(v)) { if (!(y = (f(v) << A) + B)) { if (!x) swap(a, b); Split(C(v, 0), C(a, 1), M, C(v, 0), f, 1, +1); Split(C(v, 1), C(v, 1), M, C(b, 0), f, 1, -1); break; } if (1 - y != x * 2) x ^= 1, swap(a, b); a = C(P(v) = a, x) = v; swap(v = 0, C(a, x)); } while (a > 1) a = P(Update(a)); while (b > 1) b = P(Update(b)); L = C(A, 1); M = Update(v); R = C(A, 0); } void SplitX(int d, int& L, int& l, int& M, int& r, int& R, int lpos, int rpos) { assert(lpos < rpos); Split(d, L, M, R, [lpos, rpos](int v) -> int { const int vk = Get(v).key; if (lpos <= vk and vk <= rpos) return 0; return vk < lpos ? -1 : 1; }); Split(M, l, M, r, [lpos, rpos](int v) -> int { const int vk = Get(v).key; if (lpos < vk and vk < rpos) return 0; return vk <= lpos ? -1 : 1; }); } int MergeX(int L, int l, int M, int r, int R) { return Merge(L, Merge(l, M, r), R); } int n, q, next_preorder; vector preorder, postorder; vector> graph; long long answer; class SubProblem { public: SubProblem() : tree_(0) {} /* int cnt; int sign; int sign_sum; int above; int above_add; long long above_sum; */ void Disable(int v) { Switch(v, -1); } void Enable(int v) { Switch(v, 1); } private: void Switch(int v, int sign) { Reserve(20); assert(0 <= v and v < n); assert(sign == -1 or sign == 1); int L, l, M, r, R; SplitX(tree_, L, l, M, r, R, preorder[v], postorder[v]); N& Ln = Get(L); N& Mn = Get(M); const int above = L ? Ln.sign_sum : 0; long long above_sum = 0; if (M) { above_sum = Mn.above_sum; Mn.above_add = sign; if (Mn.sign == 1) Mn.above += sign; Mn.above_sum += Mn.cnt * sign; } if (sign == 1) { assert(l == 0 and r == 0); N& ln = Get(l = New(preorder[v])); N& rn = Get(r = New(postorder[v])); ln.sign_sum = ln.sign = 1; rn.sign_sum = rn.sign = -1; ln.above_sum = ln.above = above; Update(l); Update(r); } else { l = r = 0; } if (sign == -1) { above_sum = M ? Mn.above_sum : 0; } answer += sign * above_sum; answer += sign * (long long) above * (above - 1) / 2; tree_ = MergeX(L, l, M, r, R); } int tree_; }; map subproblems; void PreorderDfs(int v) { preorder[v] = next_preorder++; for (int child : graph[v]) { PreorderDfs(child); } postorder[v] = next_preorder++; } int main() { scanf("%d%d", &n, &q); assert(1 <= n); graph.resize(n); for (int v = 1; v < n; v++) { int p; scanf("%d", &p); graph[p].push_back(v); } preorder.resize(n); postorder.resize(n); PreorderDfs(0); vector C(n), X(q); for (int v = 0; v < n; v++) { scanf("%d", &C[v]); subproblems[C[v]].Enable(v); } printf("%lld\n", answer); for (int i = 0; i < q; i++) { int X; scanf("%d", &X); const int v = (i % n); const int x = (answer + X) % n; if (C[v] != x) { subproblems[C[v]].Disable(v); subproblems[x].Enable(v); C[v] = x; } printf("%lld\n", answer); } return 0; }