Points CodeForces - 19D(线段树)

题意:有一直角坐标系;三个操作:
一: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值