题解:AT_abc421_f [ABC421F] Erase between X and Y
题意
有一个数组
1 x:将数列中所有值为x 的元素后面添加一个数i 。2 x y:设数组中元素x 出现的下标为id_x ,元素y 出现的下标为id_y ,你需要输出\sum\limits_{j = \min(id_x, id_y)} ^ {\max(id_x, id_y)} a_j 。然后将\min(id_x, id_y) + 1 \sim \max(id_x, id_y) - 1 下标之间的所有元素删除。
题目保证,任何时候数组中都不会出现重复的元素。
思路
一眼的链表。
我们建双向链表,
我们对两种操作分类讨论:
1 x:我们可以直接在链表上插入,学过链表的应该都会。时间复杂度O(1) 。2 x y:因为我们不知道到底是元素x 的位置在前还是y 的位置在前,因此我们可以用两个变量X, Y ,分别从x, y 同时 开始往后遍历,如果X 先遍历到y ,就输出X 经过的数之和,如果Y 先遍历到x ,就输出Y 经过的数之和。输出最终结果,然后删除元素x 到元素y 之间的数。我们在判断“X 先到y 还是Y 先到x ”时就可以求出来谁在前面谁在后面了,方便删除。总时间复杂度O(q) 。
AC 记录
注意事项
我们在进行所有查询之前,要先将链表所有节点进行初始化,即对于所有的
明显,正确的段应该是
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e5 + 5;
int q;
struct List{
int pre, suf;
} a[N];
void Add(int x, int i){
a[i].pre = x;
a[i].suf = a[x].suf;
a[x].suf = i;
}
void Del(int x, int y){
a[y].pre = x;
a[x].suf = y;
}
void solve(int i){
int f, x, y;
cin >> f >> x;
if(f == 1){
Add(x, i);
}else{
cin >> y;
if(a[x].suf == y || a[y].suf == x){
cout << "0\n";
return;
}
int X = x, Y = y;
ll ans1 = 0, ans2 = 0;
while(1){
if(a[X].suf == y){
ans1 += X;
ans2 = -1;
break;
}
if(a[Y].suf == x){
ans2 += Y;
ans1 = -1;
break;
}
if(X != x){
ans1 += X;
}
if(Y != y){
ans2 += Y;
}
X = a[X].suf;
Y = a[Y].suf;
}
cout << max(ans1, ans2) << '\n';
if(a[X].suf == y){
Del(x, y);
}else{
Del(y, x);
}
}
}
int main(){
ios::sync_with_stdio(false), cin.tie(0);
cin >> q;
for(int i = 0; i <= q + 1; i++){
a[i].suf = q + 1;
}
for(int i = 1; i <= q; i++){
solve(i);
}
return 0;
}