結果

問題 No.3671 Reusable Lazy Segment Tree
コンテスト
ユーザー harurun
提出日時 2026-08-05 07:49:31
言語 PyPy3
(7.3.23 + ACL)
コンパイル:
pypy3 -mpy_compile _filename_
実行:
pypy3 _filename_
結果
TLE  
実行時間 -
コード長 18,211 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 252 ms
コンパイル使用メモリ 95,944 KB
実行使用メモリ 328,704 KB
最終ジャッジ日時 2026-09-04 22:03:30
合計ジャッジ時間 14,661 ms
ジャッジサーバーID
(参考情報)
judge3_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 9 TLE * 1 -- * 9
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#!/usr/bin/env python3
from array import array
import sys

BITS = 30
VALUE_MASK = (1 << BITS) - 1
LOW15_MASK = (1 << 15) - 1
_BIT_POS_LO = tuple(tuple(b for b in range(15) if mask & (1 << b))
                     for mask in range(1 << 15))
_BIT_POS_HI = tuple(tuple(b + 15 for b in bits) for bits in _BIT_POS_LO)


def parse_input():
    data = sys.stdin.buffer.read()
    if not data or data[-1] > 32:
        data += b"\0"
    i = 0

    while data[i] <= 32:
        i += 1
    n = 0
    while data[i] > 32:
        n = n * 10 + data[i] - 48
        i += 1

    while data[i] <= 32:
        i += 1
    m = 0
    while data[i] > 32:
        m = m * 10 + data[i] - 48
        i += 1

    def read_array(length, leading_zero=False, data=data):
        nonlocal i
        out = array("I", [0]) * (length + leading_zero)
        j = 1 if leading_zero else 0
        end = j + length
        while j < end:
            while data[i] <= 32:
                i += 1
            value = 0
            while data[i] > 32:
                value = value * 10 + data[i] - 48
                i += 1
            out[j] = value
            j += 1
        return out

    initial = read_array(n)
    left_data = read_array(m, True)
    right_data = read_array(m, True)
    mask_data = read_array(m, True)
    sum_left_data = read_array(m, True)
    sum_right_data = read_array(m, True)

    while data[i] <= 32:
        i += 1
    problem_count = 0
    while data[i] > 32:
        problem_count = problem_count * 10 + data[i] - 48
        i += 1

    starts = array("I", [0]) * problem_count
    counts = array("I", [0]) * problem_count
    k = 0
    while k < problem_count:
        while data[i] <= 32:
            i += 1
        value = 0
        while data[i] > 32:
            value = value * 10 + data[i] - 48
            i += 1
        starts[k] = value

        while data[i] <= 32:
            i += 1
        value = 0
        while data[i] > 32:
            value = value * 10 + data[i] - 48
            i += 1
        counts[k] = value
        k += 1

    return (n, m, initial, left_data, right_data, mask_data,
            sum_left_data, sum_right_data, problem_count, starts, counts)


def build_tree(values):
    n = len(values)
    size = 1
    while size < n:
        size <<= 1
    nodes = size << 1

    total = array("Q", [0]) * nodes
    counts = array("I", [0]) * (nodes * BITS)
    any_bits = array("I", [0]) * nodes
    all_bits = array("I", [0]) * nodes
    lazy_and = array("I", [VALUE_MASK]) * nodes
    lazy_or = array("I", [0]) * nodes
    saved = bytearray(nodes)

    base = size
    bit_pos_lo = _BIT_POS_LO
    bit_pos_hi = _BIT_POS_HI
    low15 = LOW15_MASK
    for i, value in enumerate(values):
        p = base + i
        total[p] = value
        any_bits[p] = value
        all_bits[p] = value
        count_base = p * 30
        for b in bit_pos_lo[value & low15]:
            counts[count_base + b] = 1
        for b in bit_pos_hi[value >> 15]:
            counts[count_base + b] = 1

    for p in range(size - 1, 0, -1):
        left = p << 1
        right = left | 1
        total[p] = total[left] + total[right]
        any_bits[p] = any_bits[left] | any_bits[right]
        all_bits[p] = all_bits[left] & all_bits[right]
        count_base = p * 30
        left_base = left * 30
        right_base = right * 30
        for b in range(30):
            counts[count_base + b] = counts[left_base + b] + counts[right_base + b]

    history = []
    history_append = history.append

    def save_full(p,
                  total=total, counts=counts,
                  any_bits=any_bits, all_bits=all_bits,
                  lazy_and=lazy_and, lazy_or=lazy_or,
                  saved=saved, history_append=history_append):
        saved[p] = 1
        count_base = p * 30
        history_append((p, total[p], any_bits[p], all_bits[p],
                        lazy_and[p], lazy_or[p],
                        counts[count_base:count_base + 30]))

    def push_nonidentity(p, half, parent_and, parent_or,
                         total=total, counts=counts,
                         any_bits=any_bits, all_bits=all_bits,
                         lazy_and=lazy_and, lazy_or=lazy_or,
                         saved=saved,
                         bit_pos_lo=bit_pos_lo, bit_pos_hi=bit_pos_hi,
                         low15=low15, save_full=save_full):
        child = p << 1
        count_base = child * 30
        child_and = lazy_and[child]
        child_or = lazy_or[child]
        new_and = (child_and & parent_and) | parent_or
        new_or = (child_or & parent_and) | parent_or
        old_any = any_bits[child]
        old_all = all_bits[child]
        clear_bits = old_any & (VALUE_MASK ^ parent_and)
        set_bits = parent_or & (VALUE_MASK ^ old_all)
        changed = clear_bits | set_bits
        if changed or new_and != child_and or new_or != child_or:
            if not saved[child]:
                save_full(child)
            value = total[child]
            for b in bit_pos_lo[clear_bits & low15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            for b in bit_pos_hi[clear_bits >> 15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            for b in bit_pos_lo[set_bits & low15]:
                index = count_base + b
                old_count = counts[index]
                value += (half - old_count) << b
                counts[index] = half
            for b in bit_pos_hi[set_bits >> 15]:
                index = count_base + b
                old_count = counts[index]
                value += (half - old_count) << b
                counts[index] = half
            total[child] = value
            any_bits[child] = (old_any & parent_and) | parent_or
            all_bits[child] = (old_all & parent_and) | parent_or
            lazy_and[child] = new_and
            lazy_or[child] = new_or

        child = (p << 1) | 1
        count_base = child * 30
        child_and = lazy_and[child]
        child_or = lazy_or[child]
        new_and = (child_and & parent_and) | parent_or
        new_or = (child_or & parent_and) | parent_or
        old_any = any_bits[child]
        old_all = all_bits[child]
        clear_bits = old_any & (VALUE_MASK ^ parent_and)
        set_bits = parent_or & (VALUE_MASK ^ old_all)
        changed = clear_bits | set_bits
        if changed or new_and != child_and or new_or != child_or:
            if not saved[child]:
                save_full(child)
            value = total[child]
            for b in bit_pos_lo[clear_bits & low15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            for b in bit_pos_hi[clear_bits >> 15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            for b in bit_pos_lo[set_bits & low15]:
                index = count_base + b
                old_count = counts[index]
                value += (half - old_count) << b
                counts[index] = half
            for b in bit_pos_hi[set_bits >> 15]:
                index = count_base + b
                old_count = counts[index]
                value += (half - old_count) << b
                counts[index] = half
            total[child] = value
            any_bits[child] = (old_any & parent_and) | parent_or
            all_bits[child] = (old_all & parent_and) | parent_or
            lazy_and[child] = new_and
            lazy_or[child] = new_or

        lazy_and[p] = VALUE_MASK
        lazy_or[p] = 0

    def range_and(p, left_bound, length, query_left, query_right, mask,
                  total=total, counts=counts,
                  any_bits=any_bits, all_bits=all_bits,
                  lazy_and=lazy_and, lazy_or=lazy_or,
                  saved=saved,
                  bit_pos_lo=bit_pos_lo, bit_pos_hi=bit_pos_hi,
                  low15=low15, push_nonidentity=push_nonidentity,
                  save_full=save_full):
        if query_left <= left_bound and left_bound + length <= query_right:
            changed = any_bits[p] & (VALUE_MASK ^ mask)
            if not changed:
                return 0

            if not saved[p]:
                save_full(p)

            value = total[p]
            count_base = p * 30
            for b in bit_pos_lo[changed & low15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            for b in bit_pos_hi[changed >> 15]:
                index = count_base + b
                value -= counts[index] << b
                counts[index] = 0
            total[p] = value
            any_bits[p] &= mask
            all_bits[p] &= mask
            lazy_and[p] &= mask
            lazy_or[p] &= mask
            return changed

        half = length >> 1
        parent_and = lazy_and[p]
        parent_or = lazy_or[p]
        if parent_and != VALUE_MASK or parent_or:
            push_nonidentity(p, half, parent_and, parent_or)

        middle = left_bound + half
        if query_right <= middle:
            changed = range_and(p << 1, left_bound, half,
                                query_left, query_right, mask)
        elif query_left >= middle:
            changed = range_and(p << 1 | 1, middle, half,
                                query_left, query_right, mask)
        else:
            changed = range_and(p << 1, left_bound, half,
                                query_left, query_right, mask)
            changed |= range_and(p << 1 | 1, middle, half,
                                 query_left, query_right, mask)

        if changed:
            if not saved[p]:
                save_full(p)

            left = p << 1
            right = left | 1
            count_base = p * 30
            left_base = left * 30
            right_base = right * 30
            for b in bit_pos_lo[changed & low15]:
                counts[count_base + b] = counts[left_base + b] + counts[right_base + b]
            for b in bit_pos_hi[changed >> 15]:
                counts[count_base + b] = counts[left_base + b] + counts[right_base + b]
            total[p] = total[left] + total[right]
            any_bits[p] = any_bits[left] | any_bits[right]
            all_bits[p] = all_bits[left] & all_bits[right]

        return changed

    def range_or(p, left_bound, length, query_left, query_right, mask,
                 total=total, counts=counts,
                 any_bits=any_bits, all_bits=all_bits,
                 lazy_and=lazy_and, lazy_or=lazy_or,
                 saved=saved,
                 bit_pos_lo=bit_pos_lo, bit_pos_hi=bit_pos_hi,
                 low15=low15, push_nonidentity=push_nonidentity,
                 save_full=save_full):
        if query_left <= left_bound and left_bound + length <= query_right:
            changed = mask & (VALUE_MASK ^ all_bits[p])
            if not changed:
                return 0

            if not saved[p]:
                save_full(p)

            value = total[p]
            count_base = p * 30
            for b in bit_pos_lo[changed & low15]:
                index = count_base + b
                old_count = counts[index]
                value += (length - old_count) << b
                counts[index] = length
            for b in bit_pos_hi[changed >> 15]:
                index = count_base + b
                old_count = counts[index]
                value += (length - old_count) << b
                counts[index] = length
            total[p] = value
            any_bits[p] |= mask
            all_bits[p] |= mask
            lazy_and[p] |= mask
            lazy_or[p] |= mask
            return changed

        half = length >> 1
        parent_and = lazy_and[p]
        parent_or = lazy_or[p]
        if parent_and != VALUE_MASK or parent_or:
            push_nonidentity(p, half, parent_and, parent_or)

        middle = left_bound + half
        if query_right <= middle:
            changed = range_or(p << 1, left_bound, half,
                               query_left, query_right, mask)
        elif query_left >= middle:
            changed = range_or(p << 1 | 1, middle, half,
                               query_left, query_right, mask)
        else:
            changed = range_or(p << 1, left_bound, half,
                               query_left, query_right, mask)
            changed |= range_or(p << 1 | 1, middle, half,
                                query_left, query_right, mask)

        if changed:
            if not saved[p]:
                save_full(p)

            left = p << 1
            right = left | 1
            count_base = p * 30
            left_base = left * 30
            right_base = right * 30
            for b in bit_pos_lo[changed & low15]:
                counts[count_base + b] = counts[left_base + b] + counts[right_base + b]
            for b in bit_pos_hi[changed >> 15]:
                counts[count_base + b] = counts[left_base + b] + counts[right_base + b]
            total[p] = total[left] + total[right]
            any_bits[p] = any_bits[left] | any_bits[right]
            all_bits[p] = all_bits[left] & all_bits[right]

        return changed

    def range_sum(p, left_bound, length, query_left, query_right,
                  pending_and=VALUE_MASK, pending_or=0,
                  total=total, counts=counts,
                  any_bits=any_bits, all_bits=all_bits,
                  lazy_and=lazy_and, lazy_or=lazy_or,
                  bit_pos_lo=bit_pos_lo, bit_pos_hi=bit_pos_hi,
                  low15=low15):
        if query_left <= left_bound and left_bound + length <= query_right:
            if pending_and == VALUE_MASK and pending_or == 0:
                return total[p]
            if pending_and == pending_or:
                return length * pending_or
            value = total[p]
            count_base = p * 30
            clear_bits = any_bits[p] & (VALUE_MASK ^ pending_and)
            set_bits = pending_or & (VALUE_MASK ^ all_bits[p])
            for b in bit_pos_lo[clear_bits & low15]:
                value -= counts[count_base + b] << b
            for b in bit_pos_hi[clear_bits >> 15]:
                value -= counts[count_base + b] << b
            for b in bit_pos_lo[set_bits & low15]:
                value += (length - counts[count_base + b]) << b
            for b in bit_pos_hi[set_bits >> 15]:
                value += (length - counts[count_base + b]) << b
            return value

        node_and = lazy_and[p]
        node_or = lazy_or[p]
        child_pending_and = (node_and & pending_and) | pending_or
        child_pending_or = (node_or & pending_and) | pending_or
        half = length >> 1
        middle = left_bound + half
        if query_right <= middle:
            return range_sum(p << 1, left_bound, half,
                             query_left, query_right,
                             child_pending_and, child_pending_or)
        if query_left >= middle:
            return range_sum(p << 1 | 1, middle, half,
                             query_left, query_right,
                             child_pending_and, child_pending_or)
        return (range_sum(p << 1, left_bound, half,
                          query_left, query_right,
                          child_pending_and, child_pending_or) +
                range_sum(p << 1 | 1, middle, half,
                          query_left, query_right,
                          child_pending_and, child_pending_or))

    def begin():
        history.clear()

    def rollback():
        for h in history:
            p = h[0]
            total[p] = h[1]
            any_bits[p] = h[2]
            all_bits[p] = h[3]
            lazy_and[p] = h[4]
            lazy_or[p] = h[5]
            count_base = p * 30
            counts[count_base:count_base + 30] = h[6]
            saved[p] = 0
        history.clear()

    return size, begin, rollback, range_and, range_or, range_sum


def main():
    (n, m, initial, left_data, right_data, mask_data,
     sum_left_data, sum_right_data, problem_count,
     starts, query_counts) = parse_input()

    size, begin, rollback, range_and, range_or, range_sum = build_tree(initial)
    output = []
    output_append = output.append
    write = sys.stdout.write

    problem_index = 0
    while problem_index < problem_count:
        begin()
        y = problem_index + 1
        query_count = query_counts[problem_index]
        z = ((starts[problem_index] + 1) % m) + 1

        while query_count:
            u = left_data[z] ^ y
            if u < 1:
                u = 1
            elif u > n:
                u = n
            v = right_data[z] ^ y
            if v < 1:
                v = 1
            elif v > n:
                v = n
            if u <= v:
                update_left = u - 1
                update_right = v
            else:
                update_left = v - 1
                update_right = u

            u = sum_left_data[z] ^ y
            if u < 1:
                u = 1
            elif u > n:
                u = n
            v = sum_right_data[z] ^ y
            if v < 1:
                v = 1
            elif v > n:
                v = n
            if u <= v:
                sum_left = u - 1
                sum_right = v
            else:
                sum_left = v - 1
                sum_right = u

            update_mask = (mask_data[z] ^ y) & VALUE_MASK
            if z & 1:
                range_and(1, 0, size, update_left, update_right,
                          update_mask)
            else:
                range_or(1, 0, size, update_left, update_right,
                         update_mask)

            y = range_sum(1, 0, size, sum_left, sum_right) & VALUE_MASK
            z += 1
            if z > m:
                z = 1
            query_count -= 1

        output_append(str(y))
        rollback()
        if len(output) == 4096:
            write("\n".join(output) + "\n")
            output.clear()
        problem_index += 1

    if output:
        write("\n".join(output) + "\n")


if __name__ == "__main__":
    main()
0