在平面上进行三种操作:
1、add x y:在平面上添加一个点(x,y)
2、remove x y:将平面上的点(x,y)删除
3、find x y:在平面上寻找一个点,使这个点的横坐标大于x,纵坐标大于y,而且要求他的横坐标尽量小,如果有多个点满足,则选取横坐标尽量小的前提下,纵坐标最小的点。
方法:
将横坐标x离散化,每一个坐标x对应的y用一颗平衡树维护(C++中的set),则这颗平衡树支持增加和删除以及查找比y大的最小值的操作。
在此基础上,对于每一个询问,只需要遍历大于x的set,并且找到最小的y即可。但是这样子依次向后遍历的复杂度为O(N)的,所以要用一颗线段树来维护横坐标区间段里面y的最大值,这样就可以在O(logN)的复杂度内找到最接近x的横坐标(而且满足当前坐标的最大纵坐标大于y),然后再set里面查找最小的纵坐标即可。
#include <cstdio> #include <vector> #include <set> #include <cstring> #include <algorithm> using namespace std; #define N 200100 int n, m, A[N], my[N<<2]; set<int> a[N]; char s[10]; struct node { char op; int x, y; } q[N]; int idx(int v) { return lower_bound(A, A+m, v) - A + 1; } void update(int x, int L, int R, int rt) { if (L == R) { if (a[x].size() == 0) my[rt] = 0; else my[rt] = *a[x].rbegin(); return ; } int Mid = (L + R) >> 1; if (x <= Mid) update(x, L, Mid, rt<<1); else update(x, Mid+1, R, rt<<1|1); my[rt] = max(my[rt<<1], my[rt<<1|1]); } int query(int x, int y, int L, int R, int rt) { if (L == R) { if (my[rt] > y && x < L) return L; return 0; } int Mid = (L + R) >> 1; int t = 0; if (x < Mid && my[rt<<1] > y) t = query(x, y, L, Mid, rt<<1); if (t == 0 && my[rt<<1|1] > y) t = query(x, y, Mid+1, R, rt<<1|1); return t; } int main() { scanf("%d", &n); m = 0; for (int i=0; i<n; i++) { scanf(" %s%d%d", s, &q[i].x, &q[i].y); q[i].op = s[0]; A[m++] = q[i].x; a[i].clear(); } a[n].clear(); sort(A, A+m); m = unique(A, A+m) - A; memset(my, 0, sizeof(my)); int x, y; for (int i=0; i<n; i++) { x = idx(q[i].x), y = q[i].y; if (q[i].op == 'a') { a[x].insert(y); update(x, 1, n, 1); } else if (q[i].op == 'r') { a[x].erase(y); update(x, 1, n, 1); } else { int t = query(x, y, 1, n, 1); if (t) printf("%d %d\n", A[t-1], *a[t].upper_bound(y)); else puts("-1"); } } return 0; }