結果
問題 |
No.2338 Range AtCoder Query
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:09:29 |
言語 | PyPy3 (7.3.15) |
結果 |
WA
|
実行時間 | - |
コード長 | 8,888 bytes |
コンパイル時間 | 190 ms |
コンパイル使用メモリ | 82,180 KB |
実行使用メモリ | 457,168 KB |
最終ジャッジ日時 | 2025-05-14 13:11:27 |
合計ジャッジ時間 | 46,783 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 6 WA * 28 |
ソースコード
import sys # Set higher recursion depth if needed, although BIT operations are iterative. # sys.setrecursionlimit(200010) def solve(): # Use fast I/O input = sys.stdin.readline N, M, Q = map(int, input().split()) submissions = [] for i in range(N): line = input().split() # Store problem ID, result string, and 0-based index 'k' submissions.append({'p': int(line[0]), 's': line[1], 'k': i}) queries = [] for i in range(Q): l, r = map(int, input().split()) # Store query range [L, R] (1-based) and original query ID queries.append({'L': l, 'R': r, 'id': i}) # --- Precomputation --- # Group submission indices by problem ID problem_submissions = {} # p_id -> list of 0-based indices k for i in range(N): p = submissions[i]['p'] if p not in problem_submissions: problem_submissions[p] = [] problem_submissions[p].append(i) # Stores pairs (k', k_nextAC) for penalty calculation using 1-based indices wa_points = [] # Stores events for accepted count calculation using 1-based indices ac_events = [] # Stores the 1-based index of the last AC submission encountered for each problem ID last_ac_idx = {} # Iterate through problems to find necessary relationships for events/points generation problem_ids = list(problem_submissions.keys()) # Get keys once for efficiency for p in problem_ids: indices = problem_submissions[p] # List of 0-based indices k for problem p # Precompute the index of the next AC submission for each submission related to problem p next_ac_for_k = {} # Maps 0-based index k -> 1-based index of the next AC for problem p last_ac_k_1based_in_pass = -1 # Track the 1-based index of the last AC found in reverse pass # Iterate backwards through submissions for problem p to find the next AC efficiently for i in range(len(indices) - 1, -1, -1): k = indices[i] # Current submission's 0-based index if submissions[k]['s'] == 'AC': # Update the last seen AC index (1-based) last_ac_k_1based_in_pass = k + 1 # If an AC has been seen, store it as the 'next AC' for index k if last_ac_k_1based_in_pass != -1: # The found AC index must be strictly after the current index k if last_ac_k_1based_in_pass > k + 1: next_ac_for_k[k] = last_ac_k_1based_in_pass # Iterate forwards through submissions for problem p to generate WA points and AC events for i in range(len(indices)): k = indices[i] # Current submission's 0-based index k_1based = k + 1 # Current submission's 1-based index if submissions[k]['s'] == 'WA': # If this WA submission has a corresponding next AC if k in next_ac_for_k: k_nextAC_1based = next_ac_for_k[k] # Add a point (k', k_nextAC) for penalty calculation # x=k_1based (WA index), y=k_nextAC_1based (Next AC index) wa_points.append({'x': k_1based, 'y': k_nextAC_1based}) elif submissions[k]['s'] == 'AC': k_curr_ac_1based = k_1based # Current AC's 1-based index # Fetch the 1-based index of the previous AC for this problem, default 0 if none k_prev_ac_1based = last_ac_idx.get(p, 0) # Create events for accepted count calculation based on the interval of L values # where this AC is the first one. # Add event: effect starts at L = k_prev_ac + 1 # Sub event: effect ends at L = k_curr_ac + 1 ac_events.append({'type': 'add', 'x': k_prev_ac_1based + 1, 'k': k_curr_ac_1based}) ac_events.append({'type': 'sub', 'x': k_curr_ac_1based + 1, 'k': k_curr_ac_1based}) # Update the last seen AC index for problem p last_ac_idx[p] = k_curr_ac_1based # --- Fenwick Tree (Binary Indexed Tree - BIT) Class --- class FenwickTree: def __init__(self, size): # Initialize BIT with zeros, size+1 for 1-based indexing self.tree = [0] * (size + 1) self.size = size def add(self, i, delta): # Add delta to index i. Indices must be within [1, size] if not (1 <= i <= self.size): return # Ignore updates outside valid range # Standard BIT update: move to parent indices while i <= self.size: self.tree[i] += delta i += i & (-i) # Move to next index that covers i def query_prefix(self, i): # Query sum of values in range [1, i] # Clamp index i to valid range [0, size] if i > self.size: i = self.size if i < 0: return 0 s = 0 # Standard BIT query: move to parent indices covering prefix ending at i while i > 0: s += self.tree[i] i -= i & (-i) # Move to index covering prefix before i's range return s def query(self, l, r): # Query sum of values in range [l, r] if r < l: return 0 # Compute using prefix sums: sum(1..r) - sum(1..l-1) return self.query_prefix(r) - self.query_prefix(l - 1) # Array to store final results for each query (Accepted Count, Penalty) results = [(0, 0)] * Q # --- Calculate Penalties using Sweep Line on R --- # Sort queries by their right endpoint R queries_sorted_R = sorted(queries, key=lambda q: q['R']) # Sort WA points by their y coordinate (k_nextAC) wa_points.sort(key=lambda p: p['y']) bit_pen = FenwickTree(N) # BIT to track active WA contributions based on x coordinate (k') pt_idx = 0 # Pointer for wa_points array # Sweep line moves across R from 1 to N for q in queries_sorted_R: R = q['R'] # Current sweep line position # Add contributions from WA points whose next AC index (y coordinate) is <= R while pt_idx < len(wa_points) and wa_points[pt_idx]['y'] <= R: # Add +1 at index x (WA position k') in the BIT bit_pen.add(wa_points[pt_idx]['x'], 1) pt_idx += 1 # Query penalty for the current query (L, R) # We need count of points (x, y) such that L <= x and y <= R. # BIT state reflects points with y <= R. Query sums counts for x >= L. current_penalty = bit_pen.query(q['L'], N) # Sum counts for x in range [L, N] # Store the calculated penalty in the results array using original query ID results[q['id']] = (results[q['id']][0], current_penalty) # --- Calculate Accepted Counts using Sweep Line on L --- # Sort queries by their left endpoint L queries_sorted_L = sorted(queries, key=lambda q: q['L']) # Sort AC events by their x coordinate (effective L value) ac_events.sort(key=lambda e: e['x']) bit_acc = FenwickTree(N) # BIT to track active AC contributions based on k coordinate event_idx = 0 # Pointer for ac_events array # Sweep line moves across L from 1 to N for q in queries_sorted_L: L = q['L'] # Current sweep line position # Process all AC events whose effective L coordinate (x) is <= current L while event_idx < len(ac_events) and ac_events[event_idx]['x'] <= L: event = ac_events[event_idx] k = event['k'] # The index k (1-based) whose contribution is changing # Update BIT based on event type ('add' or 'sub') if event['type'] == 'add': bit_acc.add(k, 1) else: # 'sub' bit_acc.add(k, -1) event_idx += 1 # Query accepted count for the current query (L, R) # We need sum of active contributions for indices k in [1, R] # BIT state reflects contributions active for sweep line position L. current_acc_count = bit_acc.query(1, q['R']) # Sum contributions for k in range [1, R] # Update the results tuple with accepted count, retrieving the already computed penalty pen = results[q['id']][1] # Fetch penalty computed in the previous phase results[q['id']] = (current_acc_count, pen) # --- Output results --- # Prepare output lines efficiently output_lines = [f"{results[i][0]} {results[i][1]}" for i in range(Q)] # Print all lines at once joined by newline print('\n'.join(output_lines)) solve()