• 一些坐标上的问题可以考虑在每个坐标上取一个点,将其转换为序列问题。

坐标系上维护三种操作:加点,删点,询问一个点右上角最靠左,最下的一点

n2×105n\le 2\times 10^5

# Solutions:

只会大力 KDT,CDQKDT, CDQ 输光了

其实考虑询问以最靠左为第一关键字,那么我们从 (x0,y0)(x_0, y_0) 找到一个最小的 xx 若这一列存在成立的点,那答案就在这一列找到第一个大于 y0y_0 的就好

这启发我们每个 xx 列保留最上面一个点,然后问题变成了查询一段区间内值大于某个数的最靠前的位置,这是一个经典问题,线段树上二分即可。

为了方便的处理修改操作,我们建 2e52e5 个 set 来维护一个列上的点,那求最大值删除添加点都可以 O(1)\mathrm O(1) 解决

找到答案列后,在对应列的 set 上 upper_bound 一下就好了

这样复杂度是一个 log\log

注意在每个 set 中加入一个最小值可以更为方便地处理添加删除点时 set 为空的情况,避免了繁琐的讨论。

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* ==============================
* Author : Odalys
*
* Mail : minyuenu@gmail.com
* =============================== */
#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &a){
T w=1; a=0;
char ch=getchar();
for(;ch < '0' || ch > '9';ch=getchar()) if(ch == '-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) a=(a<<3)+(a<<1)+(ch^48);
a*=w;
}
template <typename T> inline void ckmax(T &a, T b){a = a > b ? a : b;}
template <typename T> inline void ckmin(T &a, T b){a = a < b ? a : b;}
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define vi vector<int>
#define Debug(x) cout << #x << " = " << x << endl
#define For(i,l,r) for (int i = l; i <= r; ++i)
#define foR(i,l,r) for (int i = l; i >= r; --i)
const int N = 2e5 + 10;

struct Question {
int opt, x, y;
Question (int Opt = 0, int X = 0, int Y = 0) {
opt = Opt, x = X, y = Y;
}
} s[N];
// 0 add
// 1 remove
// 2 find
int n;
int lshx[N], lshy[N];
int cntx, cnty;

set <int> mck[N];

inline void Init() {
For (i, 1, n) {
char op[8]; int x, y;
scanf ("%s", op); read(x); read(y);
if (op[0] == 'a') s[i] = Question (0, x, y);
if (op[0] == 'r') s[i] = Question (1, x, y);
if (op[0] == 'f') s[i] = Question (2, x + 1, y + 1);
lshx[++cntx] = s[i].x, lshy[++cnty] = s[i].y;
mck[i].insert(-1);
}
sort (lshx + 1, lshx + cntx + 1);
cntx = unique(lshx + 1, lshx + cntx + 1) - lshx - 1;
sort (lshy + 1, lshy + cnty + 1);
cnty = unique(lshy + 1, lshy + cnty + 1) - lshy - 1;
}

int Idx (int x) { return lower_bound(lshx + 1, lshx + cntx + 1, x) - lshx; }
int Idy (int x) { return lower_bound(lshy + 1, lshy + cnty + 1, x) - lshy; }

#define ls x << 1
#define rs x << 1 | 1
int mx[N << 2];
inline void pushup (int x) { mx[x] = max(mx[ls], mx[rs]); }
void update (int x, int l, int r, int p, int v) {
if (l == r) return mx[x] = v, void();
int mid = l + r >> 1;
if (p <= mid) update(ls, l, mid, p, v);
else update(rs, mid + 1, r, p, v);
pushup(x);
}
int query (int x, int l, int r, int X, int Y) {
if (l == r) return (mx[x] >= Y) ? l : -1;
int mid = l + r >> 1;
if (X <= mid && mx[ls] >= Y) {
int tmp = query(ls, l, mid, X, Y);
if (~tmp) return tmp;
}
if(mx[rs] >= Y) return query(rs, mid + 1, r, X, Y);
return -1;
}

void qq (int x, int l, int r) {
if (l == r) return cout << mx[x] << " ", void();
int mid = l + r >> 1;
qq(ls, l, mid);
qq(rs, mid + 1, r);
}
inline void Solve () {
For (i, 1, n) {
s[i].x = Idx(s[i].x), s[i].y = Idy(s[i].y);
if (s[i].opt == 0) {
int las = *(mck[s[i].x].rbegin());
if (s[i].y > las) update(1, 1, cntx, s[i].x, s[i].y);
mck[s[i].x].insert(s[i].y);
} // add
if (s[i].opt == 1) {
mck[s[i].x].erase(s[i].y);
update(1, 1, cntx, s[i].x, *mck[s[i].x].rbegin());
} // rem
if (s[i].opt == 2) {
int x = -1;
x = query(1, 1, cntx, s[i].x, s[i].y);
if (x == -1) puts("-1");
else {
auto it = mck[x].lower_bound(s[i].y);
if (it == mck[x].end()) {puts("-1"); continue;}
printf ("%d %d\n", lshx[x], lshy[(*it)]);
}
}
}
}

int main() {
read(n);
Init();
Solve();
}