結果
| 問題 |
No.3265 地元に帰れば天才扱い!
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-08-18 10:00:49 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
TLE
(最新)
AC
(最初)
|
| 実行時間 | - |
| コード長 | 4,958 bytes |
| コンパイル時間 | 686 ms |
| コンパイル使用メモリ | 82,220 KB |
| 実行使用メモリ | 128,956 KB |
| 最終ジャッジ日時 | 2025-09-06 12:35:11 |
| 合計ジャッジ時間 | 36,322 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 20 TLE * 1 |
ソースコード
# PyPy3 互換に翻訳した C++23 コード
import sys
import threading
from operator import add
def main():
input = sys.stdin.readline
# -- 任意の結合関数に対応したセグメント木(点更新・区間クエリ) --
class SegmentTree:
__slots__ = ('n', 'size', 'func', 'default', 'data')
def __init__(self, init_list, default, func):
# init_list: 初期値リスト
# default: 単位元
# func(a, b): 結合関数(結合的)
m = len(init_list)
n = 1
while n < m:
n <<= 1
self.n = n
self.size = m
self.func = func
self.default = default
# ツリー用の配列(サイズ 2*n)
data = [default] * (2 * n)
# 葉ノードに初期値をセット
data[n:n+m] = init_list
# 内部ノードを構築
for i in range(n-1, 0, -1):
data[i] = func(data[2*i], data[2*i+1])
self.data = data
def update(self, idx, value):
# idx の位置を value に更新
i = idx + self.n
self.data[i] = value
i >>= 1
while i:
self.data[i] = self.func(self.data[2*i], self.data[2*i+1])
i >>= 1
def query(self, left, right):
# 区間 [left, right) のクエリを実行
res_l = self.default
res_r = self.default
l = left + self.n
r = right + self.n
while l < r:
if l & 1:
res_l = self.func(res_l, self.data[l])
l += 1
if r & 1:
r -= 1
res_r = self.func(self.data[r], res_r)
l >>= 1
r >>= 1
return self.func(res_l, res_r)
# 入力読み込み
N, M = map(int, input().split())
A = [0] * N
L = [0] * N
R = [0] * N
for i in range(N):
a, l, r = map(int, input().split())
A[i] = a
# 0-based インデックスに変換
L[i] = l - 1
R[i] = r - 1
Q, = map(int, input().split())
X = [0] * Q
Y = [0] * Q
U = [0] * Q
V = [0] * Q
for i in range(Q):
x, y, u, v = map(int, input().split())
X[i] = x - 1
Y[i] = y - 1
U[i] = u - 1
V[i] = v - 1
# 初期解の計算: B_init のプレフィックス和を利用
B_init = [0] * (M + 1)
addr_of = [0] * N
# イモズ法用差分配列
imos_init = [0] * (M + 1)
for i in range(N):
addr_of[i] = i
B_init[i] = A[i]
imos_init[L[i]] += 1
# R[i]+1 が範囲内なら減算
if R[i] + 1 <= M:
imos_init[R[i] + 1] -= 1
# B_init の累積和
csum = [0] * (M + 2)
for i in range(M + 1):
csum[i+1] = csum[i] + B_init[i]
cur_ans = 0
for i in range(N):
length = R[i] - L[i] + 1
total_B = csum[R[i] + 1] - csum[L[i]]
cur_ans += length * A[i] - total_B
# セグメント木を構築
B_tree = SegmentTree(B_init, 0, add) # A を格納する木
imos_tree = SegmentTree(imos_init, 0, add) # カバレッジ数を管理する木
ans = [0] * Q
for qi in range(Q):
seg = X[qi]
# 古い区間のイモズ差分を更新
old_l, old_r = L[seg], R[seg]
cur = imos_tree.query(old_l, old_l+1) - 1
imos_tree.update(old_l, cur)
if old_r + 1 <= M:
cur2 = imos_tree.query(old_r+1, old_r+2) + 1
imos_tree.update(old_r+1, cur2)
# 古い寄与分を差し引く
cover_count = imos_tree.query(0, addr_of[seg] + 1)
sum_B = B_tree.query(old_l, old_r + 1)
cur_ans -= (old_r - old_l + 1) * A[seg] - sum_B - cover_count * A[seg]
# B_tree から削除
B_tree.update(addr_of[seg], 0)
# 新しい区間・アドレスを設定して追加
L[seg], R[seg] = U[qi], V[qi]
addr_of[seg] = Y[qi]
B_tree.update(addr_of[seg], A[seg])
# 新しい寄与分を加算
new_l, new_r = L[seg], R[seg]
cover_count = imos_tree.query(0, addr_of[seg] + 1)
sum_B = B_tree.query(new_l, new_r + 1)
cur_ans += (new_r - new_l + 1) * A[seg] - sum_B - cover_count * A[seg]
# 新しい区間のイモズ差分を登録
cur3 = imos_tree.query(new_l, new_l+1) + 1
imos_tree.update(new_l, cur3)
if new_r + 1 <= M:
cur4 = imos_tree.query(new_r+1, new_r+2) - 1
imos_tree.update(new_r+1, cur4)
ans[qi] = cur_ans
# 解答を出力
out = sys.stdout.write
for v in ans:
out(str(v) + '\n')
if __name__ == '__main__':
# PyPy3 ではスレッドで実行すると高速になる場合あり
threading.Thread(target=main).start()