G. The Great Equalizer
Tema bought an old device with a small screen and a worn-out inscription "The Great Equalizer" on the side.
The seller said that the device needs to be given an array $a$ of integers as input, after which "The Great Equalizer" will work as follows:
- Sort the current array in non-decreasing order and remove duplicate elements leaving only one occurrence of each element.
- If the current length of the array is equal to $1$, the device stops working and outputs the single number in the array — output value of the device.
- Add an arithmetic progression {$n,\ n - 1,\ n - 2,\ \ldots,\ 1$} to the current array, where $n$ is the length of the current array. In other words, $n - i$ is added to the $i$-th element of the array, when indexed from zero.
- Go to the first step.
To test the operation of the device, Tema came up with a certain array of integers $a$, and then wanted to perform $q$ operations on the array $a$ of the following type:
- Assign the value $x$ ($1 \le x \le 10^9$) to the element $a_i$ ($1 \le i \le n$).
- Give the array $a$ as input to the device and find out the result of the device's operation, while the array $a$ remains unchanged during the operation of the device.
Help Tema find out the output values of the device after each operation.
Input
The first line of the input contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases.
Then follows the description of each test case.
The first line of each test case contains a single integer $n$ ($1 \le n \le 2 \cdot 10^5$) — the size of the array $a$ that Tema initially came up with.
The second line of each test case contains $n$ integers $a_1, a_2, a_3, \ldots, a_n$ ($1 \le a_i \le 10^9$) — the elements of the array $a$.
The third line of a set contains a single integer $q$ ($1 \le q \le 2 \cdot 10^5$) — the number of operations.
Each of the next $q$ lines of a test case contains two integers $i$ ($1 \le i \le n$) and $x$ ($1 \le x \le 10^9$) - the descriptions of the operations.
It is guaranteed that the sum of the values of $n$ and the sum of the values of $q$ for all test cases do not exceed $2 \cdot 10^5$.
Output
For each test case, output $q$ integers — the output values of the device after each operation.
Example
input
4 3 2 4 8 3 1 6 2 10 3 1 5 1 2 2 2 2 1 5 3 2 5 6 7 1 2 1 7 1 7 2 5 1 2 2 7 2 2 5 2 5 1 10 6 10 1 7 4 8 2 5 1 4 2 8 3 4 1 9 3 7 3 4 3 1
output
10 12 15 4 10 8 8 9 8 12 2 14 12 12 11 11 10 11 10 11 14
Note
Let's consider the first example of the input.
Initially, the array of numbers given as input to the device will be $[6, 4, 8]$. It will change as follows: $$[6, 4, 8] \rightarrow [4, 6, 8] \rightarrow [7, 8, 9] \rightarrow [10, 10, 10] \rightarrow [10]$$
Then, the array of numbers given as input to the device will be $[6, 10, 8]$. It will change as follows: $$[6, 10, 8] \rightarrow [6, 8, 10] \rightarrow [9, 10, 11] \rightarrow [12, 12, 12] \rightarrow [12]$$
The last array of numbers given as input to the device will be $[6, 10, 1]$. It will change as follows: $$[6, 10, 1] \rightarrow [1, 6, 10] \rightarrow [4, 8, 11] \rightarrow [7, 10, 12] \rightarrow [10, 12, 13] \rightarrow [13, 14, 14] \rightarrow [13, 14] \rightarrow [15, 15] \rightarrow [15]$$
解题思路
需要观察出性质,一个数组在经过如若干次操作后得到的最终结果是什么。可以发现每次给数组加上$\{ n, n - 1, \ldots, 1 \}$后,元素间的相对大小关系没有发生变化,且相邻两个元素的差值会减小$1$。假设初始时数组排序后最大的差值是$x$,那么经过$x$次操作后数组就会剩下一个元素,又由于相对大小不变,因此数组中最大的元素(即最后一个位置的元素)每次操作都会加$1$,那么留下来的元素就会是初始数组排序后最大的元素加上$x$。
因此对于每一个询问我们要动态维护数组在排序后相邻元素最大的差值,以及最大的元素是哪个,我们可以开两个$\text{std::multiset}$ $st_1$和$st_2$来分别维护。一开始直接把数组所有元素压入$st_1$,然后再把数组排序后所有相邻元素的差值压入$st_2$。
对于每个询问,假设是把$a_x$改成$y$,那么可以理解为先删除$a_x$,再插入$y$。先在$st_1$中找到$a_x$的前驱$l$和后继$r$(如果存在的话),然后在$st_2$中删除$l$和$a_x$这两个相邻元素的差值,删除$a_x$和$r$这两个相邻元素的差值。由于$a_x$被删除,$l$和$r$变为相邻元素,因此在$st_2$中插入$l$和$r$的差值。接着由于要插入$y$,在$st_1$中找到$y$的前驱$l$和后继$r$(如果存在的话),然后在$st_2$中删除$l$和$r$这两个相邻元素的差值,再往$st_2$中插入$l$和$y$的差值,以及$y$和$r$的差值。这样就可以把信息维护好了,那么这一次询问的结果就是 *st1.rbegin() + *st2.rbegin() 。
AC代码如下,时间复杂度为$O(q \cdot \log{n})$:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 int a[N]; 9 10 void solve() { 11 int n, m; 12 scanf("%d", &n); 13 multiset<int> st1, st2; 14 for (int i = 1; i <= n; i++) { 15 scanf("%d", a + i); 16 st1.insert(a[i]); 17 } 18 for (auto it = next(st1.begin()); it != st1.end(); it++) { 19 st2.insert(*it - *prev(it)); // 插入相邻元素的差值 20 } 21 scanf("%d", &m); 22 while (m--) { 23 int x, y; 24 scanf("%d %d", &x, &y); 25 auto it = st1.find(a[x]); // 找到a[x]的迭代器 26 if (it != st1.begin()) st2.erase(st2.find(*it - *prev(it))); // 存在前驱,则删除a[x]与前驱的差值 27 if (next(it) != st1.end()) st2.erase(st2.find(*next(it) - *it)); // 存在后继,则删除a[x]与后继的差值 28 if (it != st1.begin() && next(it) != st1.end()) st2.insert(*next(it) - *prev(it)); // 同时存在前驱和后继,则前驱后继变成相邻元素,插入他们的差值 29 st1.erase(it); // 删除a[x] 30 a[x] = y; 31 st1.insert(y); // 插入y 32 it = st1.find(y); // 找到y的迭代器 33 if (it != st1.begin() && next(it) != st1.end()) st2.erase(st2.find(*next(it) - *prev(it))); // 同时存在前驱后继,前驱后继不再是相邻元素,因此删除他们的差值 34 if (it != st1.begin()) st2.insert(*it - *prev(it)); // 存在前驱,则与前驱构成相邻元素,插入差值 35 if (next(it) != st1.end()) st2.insert(*next(it) - *it); // 存在后继,则与后继构成相邻元素,插入差值 36 if (st2.empty()) printf("%d ", *st1.rbegin()); // 不存在差值,说明数组中只有一个元素 37 else printf("%d ", *st1.rbegin() + *st2.rbegin()); 38 } 39 printf("\n"); 40 } 41 42 int main() { 43 int t; 44 scanf("%d", &t); 45 while (t--) { 46 solve(); 47 } 48 49 return 0; 50 }
参考资料
Codeforces Round #894 (Div.3) Editorial:https://codeforces.com/blog/entry/119715
标签:Equalizer,Great,le,10,12,device,array,rightarrow From: https://www.cnblogs.com/onlyblues/p/17657055.html