#include using namespace std; using u32 = uint32_t; using u64 = uint64_t; constexpr u32 FULL = (1u << 30) - 1; struct Node { u64 sum = 0; u32 cnt[30]{}; // 子に対して保留されている作用: // v -> (v & lazyAnd) | lazyOr u32 lazyAnd = FULL; u32 lazyOr = 0; }; struct Backup { int index; Node node; }; int N, M; vector seg; vector lastModified; vector history; int currentVersion = 0; void saveNode(int p) { if (lastModified[p] == currentVersion) { return; } lastModified[p] = currentVersion; history.push_back({p, seg[p]}); } void build( int p, int left, int right, const vector& A ) { seg[p].lazyAnd = FULL; seg[p].lazyOr = 0; if (left == right) { seg[p].sum = A[left]; for (int bit = 0; bit < 30; ++bit) { seg[p].cnt[bit] = (A[left] >> bit) & 1u; } return; } int middle = (left + right) / 2; build(p * 2, left, middle, A); build(p * 2 + 1, middle + 1, right, A); seg[p].sum = seg[p * 2].sum + seg[p * 2 + 1].sum; for (int bit = 0; bit < 30; ++bit) { seg[p].cnt[bit] = seg[p * 2].cnt[bit] + seg[p * 2 + 1].cnt[bit]; } } void applyOr(int p, u32 mask, int length) { u32 bits = mask; while (bits != 0) { int bit = __builtin_ctz(bits); bits &= bits - 1; u32 oldCount = seg[p].cnt[bit]; if (oldCount != static_cast(length)) { seg[p].sum += static_cast(length - oldCount) << bit; seg[p].cnt[bit] = length; } } seg[p].lazyOr |= mask; } void applyAnd(int p, u32 mask) { u32 bits = FULL ^ mask; while (bits != 0) { int bit = __builtin_ctz(bits); bits &= bits - 1; u32 oldCount = seg[p].cnt[bit]; if (oldCount != 0) { seg[p].sum -= static_cast(oldCount) << bit; seg[p].cnt[bit] = 0; } } seg[p].lazyAnd &= mask; seg[p].lazyOr &= mask; } // 現在の値に // v -> (v & andMask) | orMask // を作用させる。 void applyTransform( int p, u32 andMask, u32 orMask, int length ) { // 強制的に 0 になるビット u32 clearBits = (FULL ^ andMask) & (FULL ^ orMask); while (clearBits != 0) { int bit = __builtin_ctz(clearBits); clearBits &= clearBits - 1; u32 oldCount = seg[p].cnt[bit]; if (oldCount != 0) { seg[p].sum -= static_cast(oldCount) << bit; seg[p].cnt[bit] = 0; } } // 強制的に 1 になるビット u32 setBits = orMask; while (setBits != 0) { int bit = __builtin_ctz(setBits); setBits &= setBits - 1; u32 oldCount = seg[p].cnt[bit]; if (oldCount != static_cast(length)) { seg[p].sum += static_cast(length - oldCount) << bit; seg[p].cnt[bit] = length; } } // 新しい作用を、既存の遅延作用の後に合成する。 seg[p].lazyAnd &= andMask; seg[p].lazyOr = (seg[p].lazyOr & andMask) | orMask; } void push(int p, int left, int right) { if ( seg[p].lazyAnd == FULL && seg[p].lazyOr == 0 ) { return; } saveNode(p); int middle = (left + right) / 2; int leftChild = p * 2; int rightChild = p * 2 + 1; saveNode(leftChild); saveNode(rightChild); u32 andMask = seg[p].lazyAnd; u32 orMask = seg[p].lazyOr; applyTransform( leftChild, andMask, orMask, middle - left + 1 ); applyTransform( rightChild, andMask, orMask, right - middle ); seg[p].lazyAnd = FULL; seg[p].lazyOr = 0; } void update( int p, int left, int right, int queryLeft, int queryRight, bool isOr, u32 mask, u32 affectedBits ) { saveNode(p); if (queryLeft <= left && right <= queryRight) { if (isOr) { applyOr(p, mask, right - left + 1); } else { applyAnd(p, mask); } return; } push(p, left, right); int middle = (left + right) / 2; if (queryLeft <= middle) { update( p * 2, left, middle, queryLeft, queryRight, isOr, mask, affectedBits ); } if (middle < queryRight) { update( p * 2 + 1, middle + 1, right, queryLeft, queryRight, isOr, mask, affectedBits ); } seg[p].sum = seg[p * 2].sum + seg[p * 2 + 1].sum; // OR なら mask のビット、 // AND なら mask が 0 のビットしか変化しない。 u32 bits = affectedBits; while (bits != 0) { int bit = __builtin_ctz(bits); bits &= bits - 1; seg[p].cnt[bit] = seg[p * 2].cnt[bit] + seg[p * 2 + 1].cnt[bit]; } } u64 rangeSum( int p, int left, int right, int queryLeft, int queryRight ) { if (queryLeft <= left && right <= queryRight) { return seg[p].sum; } push(p, left, right); int middle = (left + right) / 2; u64 answer = 0; if (queryLeft <= middle) { answer += rangeSum( p * 2, left, middle, queryLeft, queryRight ); } if (middle < queryRight) { answer += rangeSum( p * 2 + 1, middle + 1, right, queryLeft, queryRight ); } return answer; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N >> M; vector A(N + 1); for (int i = 1; i <= N; ++i) { cin >> A[i]; } vector l(M + 1); vector r(M + 1); vector x(M + 1); vector L(M + 1); vector R(M + 1); for (int i = 1; i <= M; ++i) { cin >> l[i]; } for (int i = 1; i <= M; ++i) { cin >> r[i]; } for (int i = 1; i <= M; ++i) { cin >> x[i]; } for (int i = 1; i <= M; ++i) { cin >> L[i]; } for (int i = 1; i <= M; ++i) { cin >> R[i]; } seg.resize(4 * N + 5); lastModified.assign(4 * N + 5, 0); build(1, 1, N, A); int Q; cin >> Q; history.reserve(200000); for (int problemIndex = 1; problemIndex <= Q; ++problemIndex) { int s, q; cin >> s >> q; ++currentVersion; history.clear(); u32 y = problemIndex; auto clampIndex = [&](u32 value) -> int { if (value == 0) { return 1; } if (value > static_cast(N)) { return N; } return static_cast(value); }; for (int j = 1; j <= q; ++j) { int z = (s + j) % M + 1; int u = clampIndex(l[z] ^ y); int v = clampIndex(r[z] ^ y); int updateLeft = min(u, v); int updateRight = max(u, v); int upperU = clampIndex(L[z] ^ y); int upperV = clampIndex(R[z] ^ y); int sumLeft = min(upperU, upperV); int sumRight = max(upperU, upperV); u32 mask = x[z] ^ y; if (z % 2 == 0) { update( 1, 1, N, updateLeft, updateRight, true, mask, mask ); } else { update( 1, 1, N, updateLeft, updateRight, false, mask, FULL ^ mask ); } y = static_cast( rangeSum( 1, 1, N, sumLeft, sumRight ) & FULL ); } cout << y << '\n'; // 配列を小問題開始前の状態に戻す。 for (const Backup& backup : history) { seg[backup.index] = backup.node; } } return 0; }