题意:二维平面三种操作,添加一个点,删除一个点,询问一个点的严格右上方中离他最近的点,若有多个则横坐标小的优先,操作次数 2 ∗ 1 0 5 2*10^5 2∗105,保证操作合法。
对横坐标离散化后,线段树叶子节点建立set,存放y坐标,那么增与删都很好做,同时线段树维护y坐标最大值,查询的时候如果左右子树同时都可能满足,则优先查询左子树,若找不到答案再查右子树,查询过程中同时使用max进行搜索剪枝。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
set<int> s[maxn<<2|1];
int maxx[maxn<<2|1];
void build(int l,int r,int k){
maxx[k]=-1;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void insert(int l,int r,int k,int id,int val){
if(l==r){
s[k].insert(val);
maxx[k]=*(--s[k].end());
return ;
}
int mid=(l+r)>>1;
if(id<=mid) insert(l,mid,k<<1,id,val);
else insert(mid+1,r,k<<1|1,id,val);
maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
}
void erase(int l,int r,int k,int id,int val){
if(l==r){
s[k].erase(s[k].find(val));
if(s[k].empty()) maxx[k]=-1;
else maxx[k]=*(--s[k].end());
return ;
}
int mid=(l+r)>>1;
if(id<=mid) erase(l,mid,k<<1,id,val);
else erase(mid+1,r,k<<1|1,id,val);
maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
}
int res=-1;
int ask(int l,int r,int k,int id,int val){
if(maxx[k]<val) return -1;
if(l==r){
if(s[k].empty()) return -1;
set<int>::iterator it=s[k].upper_bound(val);
if(it==s[k].end()) return -1;
res=l;
return (*it);
}
int mid=(l+r)>>1;
if(id>mid) return ask(mid+1,r,k<<1|1,id,val);
else{
int hh=-1;
hh=ask(l,mid,k<<1,id,val);
if(hh!=-1) return hh;
return ask(mid+1,r,k<<1|1,id,val);
}
}
int b[maxn];
int m;
void quchong(int n){
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
}
int getid(int x){ return lower_bound(b+1,b+1+m,x)-b; }
struct Node{
int type; //0 add 1 erase 2 ask
int x,y;
}a[maxn];
char ss[9];
int main(){
int q,num=0;
scanf("%d",&q);
for(int i=1;i<=q;++i){
scanf("%s%d%d",ss,&a[i].x,&a[i].y);
b[i]=a[i].x;
if(ss[0]=='a') a[i].type=0;
else if(ss[0]=='r') a[i].type=1;
else a[i].type=2;
}
quchong(q);
b[++m]=b[m-1]+1;
//for(int i=1;i<=m;++i) cout<<b[i]<<" ";cout<<endl;
build(1,m,1);
for(int i=1;i<=q;++i){
if(a[i].type==0) insert(1,m,1,getid(a[i].x),a[i].y);
else if(a[i].type==1) erase(1,m,1,getid(a[i].x),a[i].y);
else{
res=-1;
int hh=ask(1,m,1,getid(a[i].x)+1,a[i].y);
if(res==-1) printf("-1\n");
else{
printf("%d %d\n",b[res],hh);
}
}
}
return 0;
}
再来一种我自己yy的做法,现在还没有调过去2333。
用CDQ将动态问题转化为静态问题,三种操作,删除优于添加,然后是查询,按照x坐标从大到小,y从大到小,同时树状数组维护y坐标下的x+y最小,同时标记这个最小值的点的所属。
写完再更。