首先以x为第一关键字,y为第二关键字进行排序,离散化
得到一个长度为num的数组(任何一次查询对应的点都能在这个数组中找到)
对此进行建树
比如进行第i次操作
找到其在数组中对应的点pos
那么pos--->num这里面的所有点的x值都大于等于pos点
看这一段序列是否有值的纵坐标大于pos点(还要注意可能会出现x坐标相同的情况,这个其实可以通过预处理找到某一段x值都大于pos点的,我懒得写了)
线段树维护一个最大的纵坐标的值,这个是降低复杂度的关键
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL(x) (x<<1)
#define RR(x) ((x<<1)|1)
const int MAXN = 200000 + 1234;
struct Seg_Tree
{
int l, r, vmax;//vamx --> col
int mid()
{
return (l + r) >> 1;
}
} tree[MAXN * 4];
struct node
{
int l, r, op, id;
} que[MAXN], tmp[MAXN];
int mark[MAXN];
int remark[MAXN];
bool cmp(node a, node b)
{
if(a.l == b.l) return a.r < b.r;//若横坐标相同,则按纵坐标从小到大排序
return a.l < b.l;
}
void build(int l, int r, int idx)
{
tree[idx].l = l;
tree[idx].r = r;
tree[idx].vmax = 0;
if(l == r) return ;
int mid = tree[idx].mid();
build(l, mid, LL(idx));
build(mid+1, r, RR(idx));
}
void update_info(int idx)
{
tree[idx].vmax = max(tree[LL(idx)].vmax, tree[RR(idx)].vmax);
}
void insert(int col, int id, int idx)
{
if(tree[idx].l == tree[idx].r)
{
tree[idx].vmax = col;
return;
}
int mid = tree[idx].mid();
if(id > mid) insert(col, id, RR(idx));
else if(id <= mid) insert(col, id, LL(idx));
update_info(idx);
}
void remove(int id, int idx)
{
if(tree[idx].l == tree[idx].r)
{
tree[idx].vmax = 0;
return;
}
int mid = tree[idx].mid();
if(id > mid) remove(id, RR(idx));
else if(id <= mid) remove(id, LL(idx));
update_info(idx);
}
int find(int row, int col, int l, int r, int idx)//在l-->r这个区间找一个值大于row和col的
{
if(tree[idx].vmax <= col) return -1;
if(tree[idx].l == tree[idx].r)
{
if(que[remark[tree[idx].l]].l > row)
{
return remark[tree[idx].l];
}
else return -1;
}
int mid = tree[idx].mid();
//尽量找左边的
if(l <= mid)
{
//int ans = find(row, col, l, mid, LL(idx));这种错误不要再犯了!
int ans = find(row, col, l, r, LL(idx));
if(ans != -1) return ans;
}
if(r > mid)
{
//int ans = find(row, col, mid+1, r, RR(idx));
int ans = find(row, col, l, r, RR(idx));
if(ans != -1) return ans;
}
return -1;
}
int main()
{
int n;
char str[10];
int cas = 1;
while(scanf("%d", &n) != EOF)
{
if(n == 0) break;
if(cas > 1) printf("\n");
for(int i = 1; i <= n; i++)
{
scanf("%s%d%d", str, &que[i].l, &que[i].r);
tmp[i].l = que[i].l;
tmp[i].r = que[i].r;
tmp[i].id = que[i].id = i;
if(strcmp(str, "add") == 0) tmp[i].op = que[i].op = 1;
else if(strcmp(str, "remove") == 0) tmp[i].op = que[i].op = 2;
else if(strcmp(str, "find") == 0) tmp[i].op = que[i].op = 3;
}
//开始离散化
sort(tmp + 1, tmp + 1 + n, cmp);
tmp[0].l = -10000;
tmp[0].r = -10000;
int num = 0;
for(int i = 1; i <= n; i++)
{
if(tmp[i].l == tmp[i-1].l && tmp[i].r == tmp[i-1].r)
{
mark[tmp[i].id] = num;
}
else
{
++num;
mark[tmp[i].id] = num;
remark[num] = tmp[i].id;
}
}
//离散化完了以后开始建树
build(1, num, 1);
printf("Case %d:\n", cas++);
for(int i = 1; i <= n; i++)
{
if(que[i].op == 1) insert(que[i].r, mark[que[i].id], 1);
else if(que[i].op == 2) remove(mark[que[i].id], 1);
else
{
int ans = find(que[i].l, que[i].r, mark[que[i].id], num, 1);
if(ans == -1) printf("-1\n");
else printf("%d %d\n", que[ans].l, que[ans].r);
}
}
}
return 0;
}