题意:
一段序列,每一个数字的大小代表坐标位置,这些坐标位置上都有垃圾,要求将这一段序列的数字最终通过x + 1, x - 1操作移动到小于等于2个位置,垃圾移动到同一个坐标位置就可以和那个坐标位置一起移动,问最小的移动数量。
思路:
通过观察,两个以内包括两个,直接0, 其他,最后移动到只剩两个最优,那肯定是有两个要选择的,通过观察发现我不管选哪两个,最后都是整体长度的减去其中每一个相邻的位置差,头和尾的差就是整体长度,要使最小,中间相邻差最大即可。
这里注意编辑代码,可能会有一种编辑方法是不断声明迭代器,通过++ --操作,但是这样会超时,效率太低了,有两个next(it), prev(it) 这两个是针对迭代器的++ --的最快效率了
#include <bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
int n, q, op, x;
set<int> se;
multiset<int> mus;
ll sum = 0;
void add(int x)
{
se.insert(x);
auto it = se.find(x);
if (next(it) != se.end())
{
sum += *next(it) - *it; //这里用next效率快很多
mus.insert(*next(it) - *it);
}
if (it != se.begin())
{
sum += *it - *prev(it);
mus.insert(*it - *prev(it));
}
if (next(it) != se.end() && it != se.begin())
{
sum -= *next(it) - *prev(it);
mus.erase(mus.find(*next(it) - *prev(it)));
}
}
void erase(int x)
{
auto it = se.find(x);
if (next(it) != se.end())
{
sum -= *next(it) - *it;
mus.erase(mus.find(*next(it) - *it));
}
if (it != se.begin())
{
sum -= *it - *prev(it);
mus.erase(mus.find(*it - *prev(it)));
}
if (next(it) != se.end() && it != se.begin())
{
sum += *next(it) - *prev(it);
mus.insert(*next(it) - *prev(it));
}
se.erase(x);
}
int getAns()
{
if (se.size() <= 2)
return 0;
return sum - *(--mus.end());
}
#include <bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
int main()
{
/*IOS; cin.tie(0), cout.tie(0);*/
cin >> n >> q;
for (int i = 1; i <= n; ++i)
{
int temp;
cin >> temp;
add(temp);
}
cout << getAns() << endl;
while (q--)
{
cin >> op >> x;
if (op == 1)
{
add(x);
cout << getAns() << endl;
}
else
{
erase(x);
cout << getAns() << endl;
}
}
return 0;
}