/** * date : 2023-03-31 22:45:47 */ #define NDEBUG using namespace std; // intrinstic #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // utility namespace Nyaan { using ll = long long; using i64 = long long; using u64 = unsigned long long; using i128 = __int128_t; using u128 = __uint128_t; template using V = vector; template using VV = vector>; using vi = vector; using vl = vector; using vd = V; using vs = V; using vvi = vector>; using vvl = vector>; template struct P : pair { template P(Args... args) : pair(args...) {} using pair::first; using pair::second; P &operator+=(const P &r) { first += r.first; second += r.second; return *this; } P &operator-=(const P &r) { first -= r.first; second -= r.second; return *this; } P &operator*=(const P &r) { first *= r.first; second *= r.second; return *this; } template P &operator*=(const S &r) { first *= r, second *= r; return *this; } P operator+(const P &r) const { return P(*this) += r; } P operator-(const P &r) const { return P(*this) -= r; } P operator*(const P &r) const { return P(*this) *= r; } template P operator*(const S &r) const { return P(*this) *= r; } P operator-() const { return P{-first, -second}; } }; using pl = P; using pi = P; using vp = V; constexpr int inf = 1001001001; constexpr long long infLL = 4004004004004004004LL; template int sz(const T &t) { return t.size(); } template inline bool amin(T &x, U y) { return (y < x) ? (x = y, true) : false; } template inline bool amax(T &x, U y) { return (x < y) ? (x = y, true) : false; } template inline T Max(const vector &v) { return *max_element(begin(v), end(v)); } template inline T Min(const vector &v) { return *min_element(begin(v), end(v)); } template inline long long Sum(const vector &v) { return accumulate(begin(v), end(v), 0LL); } template int lb(const vector &v, const T &a) { return lower_bound(begin(v), end(v), a) - begin(v); } template int ub(const vector &v, const T &a) { return upper_bound(begin(v), end(v), a) - begin(v); } constexpr long long TEN(int n) { long long ret = 1, x = 10; for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1); return ret; } template pair mkp(const T &t, const U &u) { return make_pair(t, u); } template vector mkrui(const vector &v, bool rev = false) { vector ret(v.size() + 1); if (rev) { for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1]; } else { for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i]; } return ret; }; template vector mkuni(const vector &v) { vector ret(v); sort(ret.begin(), ret.end()); ret.erase(unique(ret.begin(), ret.end()), ret.end()); return ret; } template vector mkord(int N,F f) { vector ord(N); iota(begin(ord), end(ord), 0); sort(begin(ord), end(ord), f); return ord; } template vector mkinv(vector &v) { int max_val = *max_element(begin(v), end(v)); vector inv(max_val + 1, -1); for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i; return inv; } vector mkiota(int n) { vector ret(n); iota(begin(ret), end(ret), 0); return ret; } template T mkrev(const T &v) { T w{v}; reverse(begin(w), end(w)); return w; } template bool nxp(vector &v) { return next_permutation(begin(v), end(v)); } template using minpq = priority_queue, greater>; } // namespace Nyaan // bit operation namespace Nyaan { __attribute__((target("popcnt"))) inline int popcnt(const u64 &a) { return _mm_popcnt_u64(a); } inline int lsb(const u64 &a) { return a ? __builtin_ctzll(a) : 64; } inline int ctz(const u64 &a) { return a ? __builtin_ctzll(a) : 64; } inline int msb(const u64 &a) { return a ? 63 - __builtin_clzll(a) : -1; } template inline int gbit(const T &a, int i) { return (a >> i) & 1; } template inline void sbit(T &a, int i, bool b) { if (gbit(a, i) != b) a ^= T(1) << i; } constexpr long long PW(int n) { return 1LL << n; } constexpr long long MSK(int n) { return (1LL << n) - 1; } } // namespace Nyaan // inout namespace Nyaan { template ostream &operator<<(ostream &os, const pair &p) { os << p.first << " " << p.second; return os; } template istream &operator>>(istream &is, pair &p) { is >> p.first >> p.second; return is; } template ostream &operator<<(ostream &os, const vector &v) { int s = (int)v.size(); for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i]; return os; } template istream &operator>>(istream &is, vector &v) { for (auto &x : v) is >> x; return is; } istream &operator>>(istream &is, __int128_t &x) { string S; is >> S; x = 0; int flag = 0; for (auto &c : S) { if (c == '-') { flag = true; continue; } x *= 10; x += c - '0'; } if (flag) x = -x; return is; } istream &operator>>(istream &is, __uint128_t &x) { string S; is >> S; x = 0; for (auto &c : S) { x *= 10; x += c - '0'; } return is; } ostream &operator<<(ostream &os, __int128_t x) { if (x == 0) return os << 0; if (x < 0) os << '-', x = -x; string S; while (x) S.push_back('0' + x % 10), x /= 10; reverse(begin(S), end(S)); return os << S; } ostream &operator<<(ostream &os, __uint128_t x) { if (x == 0) return os << 0; string S; while (x) S.push_back('0' + x % 10), x /= 10; reverse(begin(S), end(S)); return os << S; } void in() {} template void in(T &t, U &...u) { cin >> t; in(u...); } void out() { cout << "\n"; } template void out(const T &t, const U &...u) { cout << t; if (sizeof...(u)) cout << sep; out(u...); } struct IoSetupNya { IoSetupNya() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(15); cerr << fixed << setprecision(7); } } iosetupnya; } // namespace Nyaan // debug #ifdef NyaanDebug #define trc(...) (void(0)) #else #define trc(...) (void(0)) #endif #ifdef NyaanLocal #define trc2(...) (void(0)) #else #define trc2(...) (void(0)) #endif // macro #define each(x, v) for (auto&& x : v) #define each2(x, y, v) for (auto&& [x, y] : v) #define all(v) (v).begin(), (v).end() #define rep(i, N) for (long long i = 0; i < (long long)(N); i++) #define repr(i, N) for (long long i = (long long)(N)-1; i >= 0; i--) #define rep1(i, N) for (long long i = 1; i <= (long long)(N); i++) #define repr1(i, N) for (long long i = (N); (long long)(i) > 0; i--) #define reg(i, a, b) for (long long i = (a); i < (b); i++) #define regr(i, a, b) for (long long i = (b)-1; i >= (a); i--) #define fi first #define se second #define ini(...) \ int __VA_ARGS__; \ in(__VA_ARGS__) #define inl(...) \ long long __VA_ARGS__; \ in(__VA_ARGS__) #define ins(...) \ string __VA_ARGS__; \ in(__VA_ARGS__) #define in2(s, t) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i]); \ } #define in3(s, t, u) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i], u[i]); \ } #define in4(s, t, u, v) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i], u[i], v[i]); \ } #define die(...) \ do { \ Nyaan::out(__VA_ARGS__); \ return; \ } while (0) namespace Nyaan { void solve(); } int main() { Nyaan::solve(); } // struct bit_vector { using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; static constexpr u32 w = 64; vector block; vector count; u32 n, zeros; inline u32 get(u32 i) const { return u32(block[i / w] >> (i % w)) & 1u; } inline void set(u32 i) { block[i / w] |= 1LL << (i % w); } bit_vector() {} bit_vector(int _n) { init(_n); } __attribute__((optimize("O3", "unroll-loops"))) void init(int _n) { n = zeros = _n; block.resize(n / w + 1, 0); count.resize(block.size(), 0); } __attribute__((target("popcnt"))) void build() { for (u32 i = 1; i < block.size(); ++i) count[i] = count[i - 1] + _mm_popcnt_u64(block[i - 1]); zeros = rank0(n); } inline u32 rank0(u32 i) const { return i - rank1(i); } __attribute__((target("bmi2,popcnt"))) inline u32 rank1(u32 i) const { return count[i / w] + _mm_popcnt_u64(_bzhi_u64(block[i / w], i % w)); } }; template struct WaveletMatrix { using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; int n, lg; vector a; vector bv; WaveletMatrix(u32 _n) : n(max(_n, 1)), a(n) {} WaveletMatrix(const vector& _a) : n(_a.size()), a(_a) { build(); } __attribute__((optimize("O3"))) void build() { lg = __lg(max(*max_element(begin(a), end(a)), 1)) + 1; bv.assign(lg, n); vector cur = a, nxt(n); for (int h = lg - 1; h >= 0; --h) { for (int i = 0; i < n; ++i) if ((cur[i] >> h) & 1) bv[h].set(i); bv[h].build(); array it{begin(nxt), begin(nxt) + bv[h].zeros}; for (int i = 0; i < n; ++i) *it[bv[h].get(i)]++ = cur[i]; swap(cur, nxt); } return; } void set(u32 i, const T& x) { assert(x >= 0); a[i] = x; } inline pair succ0(int l, int r, int h) const { return make_pair(bv[h].rank0(l), bv[h].rank0(r)); } inline pair succ1(int l, int r, int h) const { u32 l0 = bv[h].rank0(l); u32 r0 = bv[h].rank0(r); u32 zeros = bv[h].zeros; return make_pair(l + zeros - l0, r + zeros - r0); } // return a[k] T access(u32 k) const { T ret = 0; for (int h = lg - 1; h >= 0; --h) { u32 f = bv[h].get(k); ret |= f ? T(1) << h : 0; k = f ? bv[h].rank1(k) + bv[h].zeros : bv[h].rank0(k); } return ret; } // k-th (0-indexed) smallest number in a[l, r) T kth_smallest(u32 l, u32 r, u32 k) const { T res = 0; for (int h = lg - 1; h >= 0; --h) { u32 l0 = bv[h].rank0(l), r0 = bv[h].rank0(r); if (k < r0 - l0) l = l0, r = r0; else { k -= r0 - l0; res |= (T)1 << h; l += bv[h].zeros - l0; r += bv[h].zeros - r0; } } return res; } // k-th (0-indexed) largest number in a[l, r) T kth_largest(int l, int r, int k) { return kth_smallest(l, r, r - l - k - 1); } // count i s.t. (l <= i < r) && (v[i] < upper) int range_freq(int l, int r, T upper) { if (upper >= (T(1) << lg)) return r - l; int ret = 0; for (int h = lg - 1; h >= 0; --h) { bool f = (upper >> h) & 1; u32 l0 = bv[h].rank0(l), r0 = bv[h].rank0(r); if (f) { ret += r0 - l0; l += bv[h].zeros - l0; r += bv[h].zeros - r0; } else { l = l0; r = r0; } } return ret; } int range_freq(int l, int r, T lower, T upper) { return range_freq(l, r, upper) - range_freq(l, r, lower); } // max v[i] s.t. (l <= i < r) && (v[i] < upper) T prev_value(int l, int r, T upper) { int cnt = range_freq(l, r, upper); return cnt == 0 ? T(-1) : kth_smallest(l, r, cnt - 1); } // min v[i] s.t. (l <= i < r) && (lower <= v[i]) T next_value(int l, int r, T lower) { int cnt = range_freq(l, r, lower); return cnt == r - l ? T(-1) : kth_smallest(l, r, cnt); } }; /* * @brief Wavelet Matrix * @docs docs/data-structure-2d/wavelet-matrix.md */ // template struct edge { int src, to; T cost; edge(int _to, T _cost) : src(-1), to(_to), cost(_cost) {} edge(int _src, int _to, T _cost) : src(_src), to(_to), cost(_cost) {} edge &operator=(const int &x) { to = x; return *this; } operator int() const { return to; } }; template using Edges = vector>; template using WeightedGraph = vector>; using UnweightedGraph = vector>; // Input of (Unweighted) Graph UnweightedGraph graph(int N, int M = -1, bool is_directed = false, bool is_1origin = true) { UnweightedGraph g(N); if (M == -1) M = N - 1; for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; if (is_1origin) x--, y--; g[x].push_back(y); if (!is_directed) g[y].push_back(x); } return g; } // Input of Weighted Graph template WeightedGraph wgraph(int N, int M = -1, bool is_directed = false, bool is_1origin = true) { WeightedGraph g(N); if (M == -1) M = N - 1; for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; T c; cin >> c; if (is_1origin) x--, y--; g[x].emplace_back(x, y, c); if (!is_directed) g[y].emplace_back(y, x, c); } return g; } // Input of Edges template Edges esgraph(int N, int M, int is_weighted = true, bool is_1origin = true) { Edges es; for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; T c; if (is_weighted) cin >> c; else c = 1; if (is_1origin) x--, y--; es.emplace_back(x, y, c); } return es; } // Input of Adjacency Matrix template vector> adjgraph(int N, int M, T INF, int is_weighted = true, bool is_directed = false, bool is_1origin = true) { vector> d(N, vector(N, INF)); for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; T c; if (is_weighted) cin >> c; else c = 1; if (is_1origin) x--, y--; d[x][y] = c; if (!is_directed) d[y][x] = c; } return d; } /** * @brief グラフテンプレート * @docs docs/graph/graph-template.md */ // template struct HeavyLightDecomposition { private: void dfs_sz(int cur) { size[cur] = 1; for (auto& dst : g[cur]) { if (dst == par[cur]) { if (g[cur].size() >= 2 && int(dst) == int(g[cur][0])) swap(g[cur][0], g[cur][1]); else continue; } depth[dst] = depth[cur] + 1; par[dst] = cur; dfs_sz(dst); size[cur] += size[dst]; if (size[dst] > size[g[cur][0]]) { swap(dst, g[cur][0]); } } } void dfs_hld(int cur) { down[cur] = id++; for (auto dst : g[cur]) { if (dst == par[cur]) continue; nxt[dst] = (int(dst) == int(g[cur][0]) ? nxt[cur] : int(dst)); dfs_hld(dst); } up[cur] = id; } // [u, v) vector> ascend(int u, int v) const { vector> res; while (nxt[u] != nxt[v]) { res.emplace_back(down[u], down[nxt[u]]); u = par[nxt[u]]; } if (u != v) res.emplace_back(down[u], down[v] + 1); return res; } // (u, v] vector> descend(int u, int v) const { if (u == v) return {}; if (nxt[u] == nxt[v]) return {{down[u] + 1, down[v]}}; auto res = descend(u, par[nxt[v]]); res.emplace_back(down[nxt[v]], down[v]); return res; } public: G& g; int id; vector size, depth, down, up, nxt, par; HeavyLightDecomposition(G& _g, int root = 0) : g(_g), id(0), size(g.size(), 0), depth(g.size(), 0), down(g.size(), -1), up(g.size(), -1), nxt(g.size(), root), par(g.size(), root) { dfs_sz(root); dfs_hld(root); } void build(int root) { dfs_sz(root); dfs_hld(root); } pair idx(int i) const { return make_pair(down[i], up[i]); } template void path_query(int u, int v, bool vertex, const F& f) { int l = lca(u, v); for (auto&& [a, b] : ascend(u, l)) { int s = a + 1, t = b; s > t ? f(t, s) : f(s, t); } if (vertex) f(down[l], down[l] + 1); for (auto&& [a, b] : descend(l, v)) { int s = a, t = b + 1; s > t ? f(t, s) : f(s, t); } } template void path_noncommutative_query(int u, int v, bool vertex, const F& f) { int l = lca(u, v); for (auto&& [a, b] : ascend(u, l)) f(a + 1, b); if (vertex) f(down[l], down[l] + 1); for (auto&& [a, b] : descend(l, v)) f(a, b + 1); } template void subtree_query(int u, bool vertex, const F& f) { f(down[u] + int(!vertex), up[u]); } int lca(int a, int b) { while (nxt[a] != nxt[b]) { if (down[a] < down[b]) swap(a, b); a = par[nxt[a]]; } return depth[a] < depth[b] ? a : b; } int dist(int a, int b) { return depth[a] + depth[b] - depth[lca(a, b)] * 2; } }; /** * @brief Heavy Light Decomposition(重軽分解) * @docs docs/tree/heavy-light-decomposition.md */ template struct Tree { private: G& g; int root; vector> bl; vector dp; void build() { bl.resize(g.size()); dp.resize(g.size()); dfs(root, -1, 0); } void dfs(int c, int p, int _dp) { dp[c] = _dp; for (int i = p, x = -1; i != -1;) { bl[c].push_back(i); i = ++x < (int)bl[i].size() ? bl[i][x] : -1; } for (auto& d : g[c]) { if (d == p) continue; dfs(d, c, _dp + 1); } } public: Tree(G& _g, int _r = 0) : g(_g), root(_r) { build(); } int depth(int u) const { return dp[u]; } int par(int u) const { return u == root ? -1 : bl[u][0]; } int kth_ancestor(int u, int k) const { if (dp[u] < k) return -1; for (int i = k ? __lg(k) : -1; i >= 0; --i) { if ((k >> i) & 1) u = bl[u][i]; } return u; } int nxt(int s, int t) const { if (dp[s] >= dp[t]) return par(s); int u = kth_ancestor(t, dp[t] - dp[s] - 1); return bl[u][0] == s ? u : bl[s][0]; } vector path(int s, int t) const { vector pre, suf; while (dp[s] > dp[t]) { pre.push_back(s); s = bl[s][0]; } while (dp[s] < dp[t]) { suf.push_back(t); t = bl[t][0]; } while (s != t) { pre.push_back(s); suf.push_back(t); s = bl[s][0]; t = bl[t][0]; } pre.push_back(s); reverse(begin(suf), end(suf)); copy(begin(suf), end(suf), back_inserter(pre)); return pre; } int lca(int u, int v) { if (dp[u] != dp[v]) { if (dp[u] > dp[v]) swap(u, v); v = kth_ancestor(v, dp[v] - dp[u]); } if (u == v) return u; for (int i = __lg(dp[u]); i >= 0; --i) { if (dp[u] < (1 << i)) continue; if (bl[u][i] != bl[v][i]) u = bl[u][i], v = bl[v][i]; } return bl[u][0]; } }; /** * @brief 木に対する一般的なクエリ * @docs docs/tree/tree-query.md */ using namespace Nyaan; void q() { inl(N); auto g = graph(N, N - 1, false, false); { vl A(N); in(A); } HeavyLightDecomposition hld{g}; Tree tree{g}; trc(hld.down); vi init(N); rep(i, N) init[hld.down[i]] = i; WaveletMatrix wm{init}; WaveletMatrix wm2{hld.down}; ini(Q); ll a = 0, b = 0, xsum = 0; rep(q, Q) { { inl(A, B, K); // 手元だとオフラインにする 脳が壊れるので a = A; b = B; #ifndef NyaanLocal a += xsum; b += xsum * 2; a %= N; b %= N; #endif } inl(delta); int L = min(a, b); int R = max(a, b) + 1; trc(L, R); // サイズ 1 -> 例外処理 if (L + 1 == R) { out(L); xsum += L, xsum %= N; continue; } // HLD 順の中央値付近について調べればよい int S = R - L; vi kouho; if (S % 2 == 0) { kouho.push_back(wm2.kth_smallest(L, R, S / 2 - 1)); kouho.push_back(wm2.kth_smallest(L, R, S / 2)); } else { kouho.push_back(wm2.kth_smallest(L, R, S / 2)); } // 答えが複数ある場合は lambda との距離で判定 ll ans = -1, dist = inf; auto upd = [&](int x) { int d = hld.dist(delta, x); if (amin(dist, d)) ans = x; }; each(mh, kouho) { trc(mh); // 根から m_h へのパス上の頂点 vp path; auto f = [&](int u, int v) { path.emplace_back(u, v); }; hld.path_query(mh, 0, true, f); reverse(all(path)); trc(path); // 根から辿る。部分木のサイズが t 以上である最も深い点は? auto calc = [&](int t) { pi res{-1, -1}; int ok = 0, ng = sz(path); while (ok + 1 < ng) { int m = (ok + ng) / 2; int x = path[m].first; int xd = hld.down[x]; int xu = hld.up[x]; int num = wm.range_freq(xd, xu, L, R); (num >= t ? ok : ng) = m; } res.first = ok; ok = path[res.first].first; ng = path[res.first].second; while (ok + 1 < ng) { int m = (ok + ng) / 2; int xd = hld.down[m]; int xu = hld.up[m]; int num = wm.range_freq(xd, xu, L, R); (num >= t ? ok : ng) = m; } res.second = ok; return res; }; int th = (S + 1) / 2; // 最も深い頂点は? pi deep = calc(th); // 部分木のサイズが th 以上になる最も浅い頂点は? pi shallow{-1, -1}; // S が偶数の場合 if (S % 2 == 0) { // th + 1 以上で最も深い点 shallow = calc(th + 1); // 部分木のサイズの最大が S/2 ならば shallow は valid // それ以外は 1 個深い所に行く pi nxt = shallow; if (nxt.second + 1 == path[nxt.first].second) { assert(nxt.first + 1 != sz(path)); nxt.first++; nxt.second = path[nxt.first].first; } else { nxt.second++; } int nd = hld.down[nxt.second]; int nu = hld.up[nxt.second]; if (S % 2 == 0 and wm2.range_freq(nd, nu, L, R) == S / 2) { // do nothing } else { shallow = nxt; } } else { // 1 択 shallow = deep; } trc(shallow); trc(deep); int u = shallow.second; int v = deep.second; assert(hld.depth[u] <= hld.depth[v]); upd(u), upd(v); // u-v パスのうち delta への最近点は? // -> LCA を見る int w = hld.lca(v, delta); // w がパス上に載っているか? if (hld.dist(u, w) + hld.dist(w, v) == hld.dist(u, v)) { upd(w); } } out(ans); xsum += ans; xsum %= N; } } void Nyaan::solve() { int t = 1; // in(t); while (t--) q(); }