题目大意:
对一个双端队列一共有四种操作:
- 从左边添加一个元素
- 从右边添加一个元素
- 将队列中元素为 x x x的从队列中直接删除
- 询问队列中的中位数是什么,中位数位置是 ⌈ m + 1 2 ⌉ \left \lceil \frac{m+1}{2} \right \rceil ⌈2m+1⌉
询问 q ≤ 1 e 7 q\le 1e7 q≤1e7
解题思路:
- 因为每添加一个元素或者删除一个元素,中位数的位置仅仅只是向左移或右移一位,所以可以用链表来动态维护中位数的位置
- 对于删除操作,可以先将链表上的该位置标记,但不删除,直到中位数会经过该点再删除,并且根据删除位置与中位数得相对位置关系再得到中位数
- 最好用自己手写的链表,
s
t
l
stl
stl链表太容易操作失误
(说的不就是我吗) - 时间复杂度是线性的
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e7 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
list <int> l;
int q;
bool vis[maxn];
char op[maxn];
int main() {
IOS;
list<int>::iterator it;
cin >> q;
int x, y = 1, siz = 0;
int test;
for (int i = 1; i <= q; i++) {
cin >> op[i];
// int test = *it;
if (op[i] == 'L') {
op[y] = 'L';
l.push_front(y++);
if (!siz) {
// cout << "?";
it = l.begin();
}
else if ((*it) != test) it--;
if (!(siz & 1) && siz) {
it--;
while (vis[*it]) it--;
}
test = *it;
siz++;
}
else if (op[i] == 'R') {
op[y] = 'R';
l.push_back(y++);
if (!siz) {
it = l.end();//不知道为啥rbegin()用不了...
it--;
}
else if ((*it) != test) it--;
if ((siz & 1) && siz) {
it++;
while (vis[*it]) {
it = l.erase(it);// it++;
test = *it;
}
}
test = *it;
siz++;
}
else if (op[i] == 'G') {
cin >> x;
vis[x] = true;
if (siz == 1) {
siz--;
continue;
}
if (siz & 1) {
if (op[x] == 'L' && op[*it] == 'L' && (*it) < x || op[x] == 'R' && op[*it] == 'R' && (*it) > x || op[x] == 'L' && op[*it] == 'R') {
it++;
while (vis[*it]) it = l.erase(it); //it++
}
while (vis[*it]) it = l.erase(it);//it++;
}
else {
if (op[x] == 'L' && op[*it] == 'L' && (*it) > x || op[x] == 'R' && op[*it] == 'R' && (*it) < x || op[x] == 'R' && op[*it] == 'L') {
it--;
while(vis[*it]) it--;
}
while (vis[*it]) it--;
}
siz--;
test = *it;
}
else {
cout << (*it) << endl;
}
}
}