TIOJ-1305

維護一個集合,支援三種操作:

  1. 插入元素$x$
  2. 移除元素$x$
  3. 詢問集合第$k$大

指令數量$\leq 10^5$,指令參數皆可用32-bit有號整數儲存


std::set不支援第三種操作,但pbds好像可以,但我不會。
之前聽過有資結能在線處理這東西,但我忘了。
所以只好離線。
將所有元素當索引值對應到陣列,插入就將那個值+1,移除就-1,這樣就能用前綴和詢問某個元素是第幾大,因為有單調性,所以可以用二分搜找出第k大的元素。
不過值域太大,所以得離線來進行離散化。
複雜度$O(nlognlogn)$(詢問),但執行時間還算不錯,大概是二分搜跟BIT都很小吧。

不過這題很坑的地方是,上面限制的指令參數包含k,所以k不一定是正整數= =;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
/*-----------------------------------------------------------------------------------------------------*/

const int N = 100001;
bool has[N];
int bit[N], sz;

void mod(int pos, int val) {
for(; pos < N; pos+=(pos&-pos))
bit[pos] += val;
}
int que(int pos) {
int res = 0;
for(; pos; pos-=(pos&-pos))
res += bit[pos];
return res;
}

signed main() {
EmiliaMyWife

vector<pair<char, int>> query;
vector<int> arr;
string s;
int x;
while(cin >> s) {
if(s[0]=='e')
break;
cin >> x;
query.push_back({s[0], x});
if(s[0] != 'a')
arr.push_back(x);
}
sort(arr.begin(), arr.end()); arr.erase(unique(arr.begin(), arr.end()), arr.end());
#define fnd(x) (lower_bound(arr.begin(),arr.end(),(x))-arr.begin()+1)

for(auto &x : query) {
int num = x.second;
if(x.first == 'i') {
num = fnd(num);
if(!has[num])
mod(num, 1), sz++, has[num] = 1;
}
if(x.first == 'r') {
num = fnd(num);
if(has[num])
mod(num, -1), sz--, has[num] = 0;
}
if(x.first == 'a') {
if(sz < num || num<1) {
cout << "error\n";
continue;
}
int l = 1, r = N-1;
while(l < r) {
int m = (l+r)/2;
if(que(m) < num)
l = m+1;
else
r = m;
}
cout << arr[l-1] << '\n';
}
}
return 0;
}