题意:有一直角坐标系;三个操作:
一:add x y;标记(x, y)点;
二:remove x y;消除已经标记过的点(x, y)
三:find x y;在点(x, y)的右上方找到横坐标离(x, y)最近的点,若有多个满足条件的点,就找纵坐标离(x, y)最近的点,找到后输出该点坐标;如果没有就输出-1
思路:
一共2*1e5个点,但是坐标范围却达到了1e9,因此要离散化点然后根据点建一棵线段树,以实现多个查询,更新的功能
首先想办法离散化:
只有所有点都知道才能离散化点,所以必定是离线作业,把所有点都存到数组里,排序后去重,以下标为编号,这样就离散完了,unique()函数可以将相邻位置的重复数字挪到数组的最后返回最后一个不重复的位置
其次就是建树了:
首先明确功能:在查询的时候找到比x大的第一个数,并且能更新对应x上的y坐标(y有多个,即横坐标相同的点),这里只要知道同一横坐标的最大y就可以知道,有没有比所给y大的点,这样就比较明确了,区间就是离散后的x,每个结点的值就是在此区间y最大值; 所有y又是必须要存的,最好还要有顺序,这要find x y这一步直接二分找满足点,同时要能增能删,就是set无疑了,set的增删查等很方便,而且存储结构又是顺序的这样就解决问题了;
#include <bits/stdc++.h>
using namespace std;
const int maxn=200020;
struct node{
int x, y, op;
}input[maxn];
int n, cnt, x[maxn];
set<int> se[maxn];
void init(){
scanf("%d", &n);
cnt=1;
char a[10];
for(int i=0; i<n; i++){
scanf("%s%d%d", a, &input[i].x, &input[i].y);
if(a[0]=='a') input[i].op=1;
else if(a[0]=='r') input[i].op=2;
else input[i].op=3;
x[cnt++]=input[i].x;
}
}
struct Tree{
int l, r, y;
}tr[maxn<<2];
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].y=-1;
if(l==r) return;
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
}
void updata(int m, int pos){
if(tr[m].l==tr[m].r){
if(se[pos].size()!=0)
tr[m].y=*(--se[pos].end());
else
tr[m].y=-1;
return;
}
int mid=(tr[m].l+tr[m].r)>>1;
if(pos<=mid) updata(m<<1, pos);
else updata(m<<1|1, pos);
tr[m].y=max(tr[m<<1].y, tr[m<<1|1].y);
}
int query(int m, int p_x, int p_y){
if(tr[m].r<=p_x) return -1;
if(tr[m].y<=p_y) return -1;
if(tr[m].l==tr[m].r) return tr[m].l;
int t=query(m<<1, p_x, p_y);
if(t==-1) t=query(m<<1|1, p_x, p_y);
return t;
}
void solve(){
sort(x+1, x+1+cnt);
cnt=unique(x+1, x+1+cnt)-(x+1);
build(1, 1, cnt);
for(int i=0; i<n; i++){
int p_x=upper_bound(x+1, x+1+cnt, input[i].x)-(x+1);
int p_y=input[i].y;
if(input[i].op==1){
se[p_x].insert(p_y);
updata(1, p_x);
}
else if(input[i].op==2){
se[p_x].erase(p_y);
updata(1, p_x);
}
else{
int ans=query(1, p_x, p_y);
if(ans==-1) printf("-1\n");
else printf("%d %d\n", x[ans], *se[ans].upper_bound(p_y));
}
}
}
int main(){
init();
solve();
return 0;
}