G. The Great Equalizer
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 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 , the device stops working and outputs the single number in the array — output value of the device.
- Add an arithmetic progression {} to the current array, where is the length of the current array. In other words, is added to the -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 , and then wanted to perform operations on the array of the following type:
- Assign the value () to the element ().
- Give the array as input to the device and find out the result of the device's operation, while the array 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 () — the number of test cases.
Then follows the description of each test case.
The first line of each test case contains a single integer () — the size of the array that Tema initially came up with.
The second line of each test case contains integers () — the elements of the array .
The third line of a set contains a single integer () — the number of operations.
Each of the next lines of a test case contains two integers () and () - the descriptions of the operations.
It is guaranteed that the sum of the values of and the sum of the values of for all test cases do not exceed .
Output
For each test case, output 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 . It will change as follows:
Then, the array of numbers given as input to the device will be . It will change as follows:
The last array of numbers given as input to the device will be . It will change as follows:
解题思路
需要观察出性质,一个数组在经过如若干次操作后得到的最终结果是什么。可以发现每次给数组加上后,元素间的相对大小关系没有发生变化,且相邻两个元素的差值会减小。假设初始时数组排序后最大的差值是,那么经过次操作后数组就会剩下一个元素,又由于相对大小不变,因此数组中最大的元素(即最后一个位置的元素)每次操作都会加,那么留下来的元素就会是初始数组排序后最大的元素加上。
因此对于每一个询问我们要动态维护数组在排序后相邻元素最大的差值,以及最大的元素是哪个,我们可以开两个 和来分别维护。一开始直接把数组所有元素压入,然后再把数组排序后所有相邻元素的差值压入。
对于每个询问,假设是把改成,那么可以理解为先删除,再插入。先在中找到的前驱和后继(如果存在的话),然后在中删除和这两个相邻元素的差值,删除和这两个相邻元素的差值。由于被删除,和变为相邻元素,因此在中插入和的差值。接着由于要插入,在中找到的前驱和后继(如果存在的话),然后在中删除和这两个相邻元素的差值,再往中插入和的差值,以及和的差值。这样就可以把信息维护好了,那么这一次询问的结果就是 *st1.rbegin() + *st2.rbegin() 。
AC代码如下,时间复杂度为:
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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17657055.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效