链接:
Codeforces Beta Round #19 D. Points
题意
给你一个笛卡尔坐标系,现在要支持三种操作,第一种操作是添加一个点(x,y),第二种操作是删除一个点(x,y), 第三种操作是查询严格在点(x,y)右上角的点中,横坐标最小的点,如果有多个点,选择纵坐标最小的那个。
做法
首先题中给出的坐标范围都是1e9,所以需要对x轴进行离散化,建立线段树,每个节点存储区间内所有点中y的最大值,所以叶子节点存储的是当前x下y的最大值。 之后对于每个x开一个set存储横坐标为x的所有y。
之后对于操作1,2,我们只需要单点更新,并且在set中进行insert和erase。
对于操作3,我们首先转换为经典问题,求x+1到inf区间内最小的下标满足权值大于y,我们只要在线段树上优先看左子树是否有满足条件的点,转换为自问题递归求解即可,注意要用区间max进行剪枝,不然复杂度会退化。
这样我们就知道最小的存在大于y的下标x,之后在x所在的set中upper_bound查找第一个大于y的值即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 2e5+5;
struct T
{
int l,r,mid;
int val,id;
}tree[maxn<<2];
multiset<int> s[maxn<<2];
void push_up(int rt)
{
tree[rt].val=max(tree[rt<<1].val,tree[rt<<1|1].val);
}
void build(int rt,int l,int r)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].val=0;
if(l==r)
{
s[l].insert(-1);
tree[rt].val=-1;
return ;
}
int mid=tree[rt].mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
return ;
}
void update(int rt,int pos,int val,int flag)
{
if(tree[rt].l==tree[rt].r)//递归到叶子节点更新set
{
if(flag==0) s[tree[rt].l].erase(val);
else s[tree[rt].l].insert(val);
tree[rt].id=pos;
tree[rt].val=*(s[tree[rt].l].rbegin());
return ;
}
if(pos<=tree[rt].mid) update(rt<<1,pos,val,flag);
else update(rt<<1|1,pos,val,flag);
push_up(rt);
return ;
}
int query(int rt,int val,int l,int r)
{
if(tree[rt].l>r||tree[rt].r<l) return -1;
if(tree[rt].l>=l&&tree[rt].r<=r)//区间最大值进行剪枝
{
if(tree[rt].val<=val) return -1;
}
if(tree[rt].l==tree[rt].r) return tree[rt].id;
if(tree[rt].mid>=l)//优先看左区间是否有满足情况的点
{
int res=query(rt<<1,val,l,r);
if(res!=-1) return res;
}
if(tree[rt].mid<r)
{
int res=query(rt<<1|1,val,l,r);
if(res!=-1) return res;
}
return -1;
}
struct data
{
int flag,x,y;
}p[maxn];
char op[maxn];
int d;
int a[maxn];//原数组
int b[maxn];//每个位置离散后的值
int c[maxn];//表示离散后为i的原来的值为c[i]
int Hash[maxn];//hash去重数组
void GetHash(int a[],int n)
{
for(int i=1;i<=n;i++) Hash[i]=a[i];
sort(Hash+1,Hash+1+n);
d=unique(Hash+1,Hash+1+n)-Hash-1;
for(int i=1;i<=n;i++)
{
b[i]=lower_bound(Hash+1,Hash+1+d,a[i])-Hash;
c[b[i]]=a[i];
}
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s%d%d", op,&x,&y);
if(op[0]=='a') p[i].flag=1;
else if(op[0]=='r') p[i].flag=2;
else p[i].flag=3;
p[i].x=x;
p[i].y=y;
a[i]=x;
}
GetHash(a,n);//对x轴进行离散化
build(1,1,d);//对x轴建立线段树
for(int i=1;i<=n;i++)
{
if(p[i].flag==1) update(1,b[i],p[i].y,1);
else if(p[i].flag==2) update(1,b[i],p[i].y,0);
else
{
int res=query(1,p[i].y,b[i]+1,d);
if(res==-1) printf("-1\n");
else
{
set<int>::iterator it = s[res].upper_bound(p[i].y);
printf("%d %d\n",c[res],(*it));
}
}
}
return 0;
}