E - 信号変換器の出力種類数 / Number of Distinct Outputs of a Signal Converter 解説 by admin
Claude 4.6 Opus (Thinking)Overview
Given an \(N\)-step signal converter, we need to compute the output \(F(s)\) for each input \(s\), and then efficiently count the number of distinct values of \(F(s)\) within the interval \([A_j, B_j]\) for each query.
Analysis
Step 1: Computing \(F(s)\)
First, we need to compute the output \(F(s)\) for all input values \(s\) (\(1 \leq s \leq K\)). By straightforwardly simulating the \(N\) steps for each \(s\), we can compute this in \(O(NK)\). Since the constraints guarantee \(N \times K \leq 10^7\), this is sufficiently fast.
For example, with \(K=5\), \(N=2\), and steps \((2, 4, 3)\) and \((3, 5, 1)\):
| \(s\) | After Step 1 | After Step 2 = \(F(s)\) |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 3 | 1 |
| 3 | 3 | 1 |
| 4 | 3 | 1 |
| 5 | 5 | 1 |
Step 2: Counting Distinct Values in an Interval
Once \(F(s)\) is computed, the problem reduces to the well-known problem of “finding the number of distinct values in the interval \([A_j, B_j]\) of the array \(F[1], F[2], \ldots, F[K]\).”
Naive approach: For each query, scan the interval and insert values into a set → \(O(QK)\), which risks TLE.
Efficient approach: Use offline query processing + BIT (Binary Indexed Tree).
Algorithm
We use the classic technique for finding the number of distinct values in an interval.
- Sort the queries in ascending order of their right endpoint \(B_j\).
- Scan the array \(F\) from left to right (\(s = 1, 2, \ldots, K\)).
- When we see \(F[s] = v\):
- If value \(v\) has previously appeared at position \(\text{last}[v]\), subtract \(-1\) at position \(\text{last}[v]\) in the BIT (remove the old occurrence).
- Add \(+1\) at position \(s\) in the BIT (record the latest occurrence).
- Update \(\text{last}[v] = s\).
- When the scan position \(s\) reaches a query’s right endpoint \(B_j\), compute the sum over interval \([A_j, B_j]\) using the BIT.
Why this is correct:
For each value \(v\), only its rightmost occurrence within the scanned range has \(+1\) in the BIT. At the time query \([A_j, B_j]\) is processed, the scan over the range \(s \leq B_j\) is complete. If value \(v\) appears at least once in the interval \([A_j, B_j]\), its rightmost occurrence is within \([A_j, B_j]\), so it is correctly counted by the BIT’s range sum.
Complexity
- Time complexity: \(O(NK + K \log K + Q \log K)\)
- \(O(NK)\) for computing \(F(s)\)
- \(O(K \log K)\) for scanning and BIT operations
- \(O(Q \log K)\) for answering queries
- Since the constraint guarantees \(NK \leq 10^7\), the overall computation is sufficiently fast
- Space complexity: \(O(N + K + Q)\)
Implementation Notes
BIT (Fenwick Tree) usage: A data structure that supports point updates (\(+1\) / \(-1\)) and range sum queries in \(O(\log K)\). The sum over interval \([l, r]\) is computed as
query(r) - query(l-1).Offline processing: By sorting queries by their right endpoint and processing them simultaneously with the scan, we only need to maintain the “latest occurrence position” for each value.
lastarray: For each value \(v\) (\(1 \leq v \leq K\)), records the position \(s\) where \(F[s] = v\) was last seen. The initial value is \(0\) (not yet seen).Source Code
#include <bits/stdc++.h>
using namespace std;
struct BIT {
vector<int> tree;
int n;
BIT(int n) : n(n), tree(n+1, 0) {}
void update(int i, int val) {
for (; i <= n; i += i & (-i))
tree[i] += val;
}
int query(int i) {
int s = 0;
for (; i > 0; i -= i & (-i))
s += tree[i];
return s;
}
int query(int l, int r) {
return query(r) - query(l-1);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, K, Q;
cin >> N >> K >> Q;
vector<int> L(N), R(N), X(N);
for (int i = 0; i < N; i++) {
cin >> L[i] >> R[i] >> X[i];
}
// Compute F[s] for all s from 1 to K
vector<int> F(K+1);
for (int s = 1; s <= K; s++) {
int v = s;
for (int i = 0; i < N; i++) {
if (L[i] <= v && v <= R[i]) {
v = X[i];
}
}
F[s] = v;
}
// Read queries
vector<int> A(Q), B(Q), ans(Q);
vector<pair<int,int>> queries(Q);
for (int j = 0; j < Q; j++) {
cin >> A[j] >> B[j];
queries[j] = {B[j], j};
}
// Sort queries by right endpoint
sort(queries.begin(), queries.end());
// Process using BIT (offline, sweep right endpoint)
BIT bit(K);
vector<int> last(K+1, 0);
int qi = 0;
for (int s = 1; s <= K; s++) {
int v = F[s];
if (last[v] > 0) {
bit.update(last[v], -1);
}
bit.update(s, 1);
last[v] = s;
while (qi < Q && queries[qi].first == s) {
int j = queries[qi].second;
ans[j] = bit.query(A[j], B[j]);
qi++;
}
}
for (int j = 0; j < Q; j++) {
cout << ans[j] << '\n';
}
return 0;
}
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: