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 a of integers as input, after which "The Great Equalizer" will work as follows:

  1. Sort the current array in non-decreasing order and remove duplicate elements leaving only one occurrence of each element.
  2. 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.
  3. Add an arithmetic progression {n, n1, n2, , 1} to the current array, where n is the length of the current array. In other words, ni is added to the i-th element of the array, when indexed from zero.
  4. 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:

  1. Assign the value x (1x109) to the element ai (1in).
  2. 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 (1t104) — 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 (1n2105) — the size of the array a that Tema initially came up with.

The second line of each test case contains n integers a1,a2,a3,,an (1ai109) — the elements of the array a.

The third line of a set contains a single integer q (1q2105) — the number of operations.

Each of the next q lines of a test case contains two integers i (1in) and x (1x109) - 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 2105.

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][4,6,8][7,8,9][10,10,10][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][6,8,10][9,10,11][12,12,12][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][1,6,10][4,8,11][7,10,12][10,12,13][13,14,14][13,14][15,15][15]

 

解题思路

  需要观察出性质,一个数组在经过如若干次操作后得到的最终结果是什么。可以发现每次给数组加上{n,n1,,1}后,元素间的相对大小关系没有发生变化,且相邻两个元素的差值会减小1。假设初始时数组排序后最大的差值是x,那么经过x次操作后数组就会剩下一个元素,又由于相对大小不变,因此数组中最大的元素(即最后一个位置的元素)每次操作都会加1,那么留下来的元素就会是初始数组排序后最大的元素加上x

  因此对于每一个询问我们要动态维护数组在排序后相邻元素最大的差值,以及最大的元素是哪个,我们可以开两个std::multiset st1st2来分别维护。一开始直接把数组所有元素压入st1,然后再把数组排序后所有相邻元素的差值压入st2

  对于每个询问,假设是把ax改成y,那么可以理解为先删除ax,再插入y。先在st1中找到ax的前驱l和后继r(如果存在的话),然后在st2中删除lax这两个相邻元素的差值,删除axr这两个相邻元素的差值。由于ax被删除,lr变为相邻元素,因此在st2中插入lr的差值。接着由于要插入y,在st1中找到y的前驱l和后继r(如果存在的话),然后在st2中删除lr这两个相邻元素的差值,再往st2中插入ly的差值,以及yr的差值。这样就可以把信息维护好了,那么这一次询问的结果就是 *st1.rbegin() + *st2.rbegin() 。

  AC代码如下,时间复杂度为O(qlogn)

复制代码
 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

posted @   onlyblues  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示