D. Array Repetition
Jayden has an array $a$ which is initially empty. There are $n$ operations of two types he must perform in the given order.
- Jayden appends an integer $x$ ($1 \leq x \leq n$) to the end of array $a$.
- Jayden appends $x$ copies of array $a$ to the end of array $a$. In other words, array $a$ becomes $[a,\underbrace{a,\ldots,a}_{x}]$. It is guaranteed that he has done at least one operation of the first type before this.
Jayden has $q$ queries. For each query, you must tell him the $k$-th element of array $a$. The elements of the array are numbered from $1$.
Input
Each test consists of multiple test cases. The first line contains a single integer $t$ ($1 \leq t \leq 5000$) — the number of test cases. The description of the test cases follows.
The first line of each test case contains two integers $n$ and $q$ ($1 \leq n, q \leq 10^5$) — the number of operations and the number of queries.
The following $n$ lines describe the operations. Each line contains two integers $b$ and $x$ ($b \in \{1, 2\}$), where $b$ denotes the type of operation. If $b=1$, then $x$ ($1 \leq x \leq n$) is the integer Jayden appends to the end of the array. If $b=2$, then $x$ ($1 \leq x \leq 10^9$) is the number of copies Jayden appends to the end of the array.
The next line of each test case contains $q$ integers $k_1, k_2, \ldots, k_q$ ($1 \leq k_i \leq \min(10^{18}, c)$), which denote the queries, where $c$ is the size of the array after finishing all $n$ operations.
It is guaranteed that the sum of $n$ and the sum of $q$ over all test cases does not exceed $10^5$.
Output
For each test case, output $q$ integers — answers to Jayden's queries.
Example
input
4
5 10
1 1
1 2
2 1
1 3
2 3
1 2 3 4 5 6 14 15 16 20
10 10
1 3
1 8
2 15
1 6
1 9
1 1
2 6
1 1
2 12
2 10
32752 25178 3198 3199 2460 2461 31450 33260 9016 4996
12 5
1 6
1 11
2 392130334
1 4
2 744811750
1 10
1 5
2 209373780
2 178928984
1 3
2 658326464
2 1000000000
914576963034536490 640707385283752918 636773368365261971 584126563607944922 1000000000000000000
2 2
1 1
1 2
1 2
output
1 2 1 2 3 1 2 3 1 3
9 8 1 3 1 3 6 3 8 8
11 11 11 10 11
1 2
Note
In the first test case:
- After the first operation $a = [1]$;
- After the second operation $a = [1, 2]$;
- After the third operation $a = [1, 2, 1, 2]$;
- After the fourth operation $a = [1, 2, 1, 2, 3]$;
- After the fifth operation $a = [1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3]$.
In the fourth test case, after all operations $a = [1, 2]$.
解题思路
首先我们不可能根据操作把数组 $a$ 模拟建出来,否则时间和空间复杂度都会爆掉,意味着一定是通过“压缩”的方式来存储数组 $a$ 的信息。
考虑用链式结构依次存储每个状态 $a$ 的信息,那么每个节点存储哪些参数呢?对于操作 $2$,显然要记录拷贝前 $a$ 的大小(也就是当前 $a$ 的大小),记作 $sz$,以及拷贝后的数量 $x+1$,记作 $c$。这样对于当前节点的两个参数 $sz$ 与 $c$,就可以得知当前的 $a$ 是将前一个节点所表示的数组拷贝 $c$ 份得到的,大小为 $sz \cdot c$。
另外对于操作 $1$,我们还需要在节点中记录数组的最后一个元素是什么,如果有连续的操作 $1$,为了避免开额外的节点我们在节点中用一个 std::vector
来记录连续的操作 $1$ 压入的元素,只有在操作 $2$ 时才开新的节点。由于询问的下标不超过 $10^{18}$ 这样做就可以保证在 $n$ 次操作后节点的数量不超过 $61$ 个(因为 $2^{61} > 10^{18}$,同时当数组 $a$ 的大小不超过 $10^{18}$ 才执行操作)。
因此新的节点的参数 $sz$ 就是前一个节点的 $sz \cdot c + \text{size}(q)$,$\text{size}(q)$ 是std::vector
的大小。另外只有在当前数组大小不超过 $10^{18}$ 时才进行拷贝,同时还要保证拷贝后的数组大小不超过 $10^{18}$,即新节点的参数 $c$ 实际上应该是 $\min\left\{ x+1, \, \left\lceil \frac{10^{18}}{sz} \right\rceil \right\}$,这里的 $sz$ 是新节点的。
对于询问 $x$,只需从后往前依次枚举每个节点,对于当前节点状态的数组,记 $s = sz \cdot c$,表示上一个状态的数组拷贝了 $c$ 份后的大小。如果 $x \in \left[ s + 1, \, s + \text{size}(q) \right]$,那么很明显答案就是 $q[x-s-1]$。否则 $x$ 的位置在某份拷贝的数组中(即大小为 $sz$ 的数组),令 $x \gets (x-1) \bmod sz + 1$,得到其所在拷贝的数组的下标,然后遍历到前一个节点用同样的方法继续处理。
AC 代码如下,时间复杂度为 $O(q \cdot \log{A})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Node {
LL sz, c;
vector<int> q;
};
void solve() {
int n, m;
cin >> n >> m;
vector<Node> p({{0}});
while (n--) {
int op, x;
cin >> op >> x;
if (op == 1) {
p.back().q.push_back(x);
}
else {
LL sz = p.back().sz * p.back().c + p.back().q.size();
if (sz < (LL)1e18) p.push_back({sz, min(x + 1ll, ((LL)1e18 + sz - 1) / sz)});
}
}
while (m--) {
LL x;
cin >> x;
for (int i = p.size() - 1; i >= 0; i--) {
LL sz = p[i].sz * p[i].c;
if (x > sz) {
cout << p[i].q[x - sz - 1] << ' ';
break;
}
else {
x = (x - 1) % p[i].sz + 1;
}
}
}
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round 919 (Div. 2) 题解:https://www.cnblogs.com/zsc985246/p/17963255
Editorial for Codeforces Round #919 (Div. 2):https://codeforces.com/blog/entry/122560
标签:sz,10,array,leq,test,Array,Repetition,节点 From: https://www.cnblogs.com/onlyblues/p/17975392