[DTOI 2023] B. 去年 11 月卵梦蕾简易钨丝
题目背景
大样例已修复
题目描述
给定序列
{
a
n
}
\{a_n\}
{an},支持两种形如 opt x
操作:
-
1 x
:删除一个数 x x x,若序列中没有 x x x,则输出 − 1 -1 −1 并跳过本次操作,若有多个 x x x,则仅删除一个。 -
2 x
:向序列中插入一个数 x x x。
对于每个未被跳过的操作,试求出 a a a 的一个排列 p p p,最小化 ∑ i = 1 n ∣ p i + 1 − p i ∣ \sum \limits_{i=1}^{n} \lvert p_{i+1}-p_i\rvert i=1∑n∣pi+1−pi∣ 的值,即最小化 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert ∣p2−p1∣+∣p3−p2∣+⋯+∣pn+1−pn∣ 的值,其中 p n + 1 = p 1 p_{n+1}=p_1 pn+1=p1。
保证任意时刻序列内至少有 1 1 1 个数。
p p p 是 a a a 的排列当且仅当对于 ∀ x \forall x ∀x, ∑ [ p i = x ] = ∑ [ a i = x ] \sum [p_i=x]=\sum [a_i=x] ∑[pi=x]=∑[ai=x]。
简而言之, p p p 是 a a a 经过某种方式重排后的结果。
例如 { 1 , 1 , 4 , 5 , 1 , 4 } \{1,1,4,5,1,4\} {1,1,4,5,1,4} 是 { 1 , 5 , 4 , 1 , 4 , 1 } \{1,5,4,1,4,1\} {1,5,4,1,4,1} 的一个排列,但是 { 1 , 5 , 4 , 1 , 4 , 7 } \{1,5,4,1,4,7\} {1,5,4,1,4,7} 不是。
输入格式
输入共 q + 2 q + 2 q+2 行。
第 1 1 1 行两个正整数 n , q n, q n,q。
第 2 2 2 行 n n n 个非负整数 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an,代表初始的序列。
第 3 ∼ q + 2 3 \sim q + 2 3∼q+2 行,每行两个数 o p t , x opt, x opt,x , 代表一个询问。
输出格式
输出有多行。
每行输出
1
1
1 个数,代表一个未被忽略的询问的答案,否则输出 -1
。
样例 #1
样例输入 #1
5 3
1 2 3 4 10
1 4
1 10
2 9
样例输出 #1
18
4
16
提示
【样例 1 解释】
对于第一个询问,删除了序列中的数 4 4 4,则当前序列为$ 1, 2, 3, 10 $, 可以证明 18 18 18 为当前序列的最小答案。
对于第二个询问,删除了序列中的数 10 10 10,则当前序列为$ 1, 2, 3 $, 可以证明 4 4 4 为当前序列的最小答案。
对于第三个询问,向序列中添加了一个数 9 9 9,则当前序列为$ 1, 2, 3, 9 $, 可以证明 16 16 16 为当前序列的最小答案。
【样例 2】
见附加文件中的 abs/abs2.in
与 abs/abs2.out
。
该样例满足测试点 1 ∼ 4 1\sim 4 1∼4 的限制。
【样例 3】
见附加文件中的 abs/abs3.in
与 abs/abs3.out
。
该样例满足测试点 7 ∼ 10 7\sim 10 7∼10 的限制。
【数据范围与提示】
记 w w w 为值域大小,对于所有测试数据,保证 n , q ≤ 1 0 6 n,q\leq 10^6 n,q≤106, 0 ≤ w ≤ 1 0 6 0\leq w\leq 10^6 0≤w≤106。
每个测试点的具体限制见下表:
测试点编号 | n , q ≤ n,q\leq n,q≤ | w w w |
---|---|---|
1 ∼ 4 1\sim 4 1∼4 | 100 100 100 | 10 10 10 |
5 ∼ 6 5\sim 6 5∼6 | 1 0 3 10^3 103 | 1 0 3 10^3 103 |
7 ∼ 10 7\sim 10 7∼10 | 1 0 6 10^6 106 | 1 0 6 10^6 106 |
思路
- 首先,我们先算:最小化 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert ∣p2−p1∣+∣p3−p2∣+⋯+∣pn+1−pn∣ 的值。
观察式子 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert ∣p2−p1∣+∣p3−p2∣+⋯+∣pn+1−pn∣(下记为 S S S),这里的若干个绝对值符号给了我们一些思路,我们设想一种特殊情况:
若满足 ∀ i ∈ [ 1 , n − 1 ] \forall i \in [1, n - 1] ∀i∈[1,n−1],都有 p i + 1 ≥ p i p_{i + 1} \ge p_{i} pi+1≥pi,则有:
S
=
p
2
−
p
1
+
p
3
−
p
2
+
⋯
+
p
k
−
p
k
−
1
+
p
k
+
1
−
p
k
+
⋯
+
p
n
−
p
n
−
1
−
p
n
+
1
+
p
n
S= p_2 - p_1 + p_3 - p_2 + \dots + p_{k} - p_{k - 1} + p_{k + 1} - p_{k} + \dots + p_n - p_{n - 1} - p_{n + 1} + p_n
S=p2−p1+p3−p2+⋯+pk−pk−1+pk+1−pk+⋯+pn−pn−1−pn+1+pn
=
p
n
−
p
1
+
p
n
−
p
n
+
1
= p_n - p_1 + p_n - p_{n + 1}
=pn−p1+pn−pn+1
=
2
(
p
n
−
p
1
)
= 2 (p_n - p_1)
=2(pn−p1)
那么我们什么时候取等呢?
- 剩下的我们就维护最大值的最小值,具体见我代码
AC代码
//xxsbhctjbyct
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6+10;
int S[N];
int w[N],b[N],cnt;
int n,q;
int maxv,minv=2e9;
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>w[i];
S[w[i]]++;
maxv=max(maxv,w[i]);
minv=min(minv,w[i]);
}
while(q--){
int op,x;
cin>>op>>x;
cnt=0;
int a=minv,b=maxv;
if(op==1){
if(S[x]==0){
puts("-1");
continue;
}
S[x]--;
//找次大值
if(x==maxv&&S[x]==0){
for(int i=x;i>=1;i--){
if(S[i]){
b=i;
break;
}
}
}
//找次小值
if(x==minv&&S[x]==0){
for(int i=x;i<N;i++){
if(S[i]){
a=i;
break;
}
}
}
maxv=b,minv=a;
// cout<<"cnt="<<cnt<<endl;
cout<<(2*(b-a))<<endl;
}else{
S[x]++;
if(x>maxv){
b=x;
maxv=x;
}
if(x<minv){
a=x;
minv=x;
}
// cout<<minv<<" "<<maxv<<endl;
// cout<<"cnt="<<cnt<<endl;
cout<<(2*(b-a))<<endl;
}
}
return 0;
}