Codeforces Beta Round #19 D-Points(树状数组+离散化)

Codeforces Beta Round #19

D-Points

题目

在这里插入图片描述

题目大意

     和以前在POJ做的的数星星差不多,POJ数星星,这里也是在笛卡尔坐标系上有多个点,只不过现在对点有增删操作,并且最一开始坐标系上是没有点的,并且查找的是该最靠近查找点的最左下的点。

样例

输入样例

case 1:

7
add 1 1
add 3 4
find 0 0
remove 1 1
find 0 0
add 1 1
find 0 0

case 2:

13
add 5 5
add 5 6
add 5 7
add 6 5
add 6 6
add 6 7
add 7 5
add 7 6
add 7 7
find 6 6
remove 7 7
find 6 6
find 4 4

输出样例

case 1:

1 1
3 4
1 1

case 2:

7 7
-1
5 5

题解

我们遇到的问题

  • 用什么数据结构去维护我们的坐标系?
  • 怎样准确并快速的搜索到我们的答案搜索到?
  • 由于该问题发生在二维笛卡尔坐标系,如果我们利用二维数据结构一定会浪费大量的空间,甚至发生内存的溢出,如何将二维数据结构,转换成一维的?
  • 数据大小1e9难道我们要开1e9的空间维护数据吗?

解决方法

  • 首先对于数据的增改查,我们首先想到的是利用树状数组或者是线段树进行数据的维护,其效率应该是最高的。我们选择用树状数组,因为线段树的代码有点长( •̀ ω •́ )✧
  • 对于答案的搜索,我们可以遍历每一个管辖区间,利用二分查找寻找我们的最优解,由于树状数组本身的特性加上我们的查找是基于二分的方法来找的所以复杂度不会太高
  • 如何将二维树状数组转换为一维树状数组?我们建立树状数组可以单单只利用y坐标,每个树状数组里存一个set集合,对应的set集合里就是对应y坐标的所有坐标点。为什么要用y不用x,这是从数星星那个题得出的经验
  • 在创建和维护树状数组的时候,需要对 起点为N - a.y的点到 x-lowbit(x) 的点以步长为 x+lowbit(x) 进行维护,即需要维护所有包含当前节点 a.y 的管辖区间的值。其中 N 是该数组的最大长度、维护树状数组的节点 这里看不懂的建议再仔细研究一下树状数组的基本结构 由于起点为N - a.y,所以数组的最大长度应该大于a.y而我们的a.y代表的是纵坐标 (我们上一步说利用纵坐标来建立树状数组 ) ,而纵坐标最大时1e9显然时会炸内存。 这里就需要利用离散化,下面时离散化的步骤:
    • 首先将所有的纵坐标排一下序,并且去重
    • 离散化后的值就是,排好序后其对应的下标,可以利用二分查找寻找下标
    • 将离散化后的值和原始数值进行一个映射处理,方便最后得出的答案不会受到影响
    • 将原始数值彻底更新为离散化后的值
//b是存储的纵坐标,v里放的是坐标,mp是映射
sort(b.begin(),b.end());
int m = unique(b.begin(),b.end()) - b.begin();
for (int i = 0; i < v.size(); ++i) {
   int pos = lower_bound(b.begin(),b.begin()+m,v[i].y) - b.begin();
   mp[pos] = v[i].y; //不要用map,会超时,可以考虑用unordered_map
   v[i].y = pos;
}

代码

#include<bits/stdc++.h>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&(-x))
#define fa(x)     (x+lowbit(x))
#define left(x)   (x-lowbit(x))
#define int long long
using namespace std;

const int N = 200000+10;
const int INF = 0x3f3f3f3f;
set<pair<int,int>> sum[N];
unordered_map<int, int> mp;

struct Point{
    int x,y;
};
//增加节点
void add(Point a){
    int p = N - a.y;
    for( ; p < N; p = fa(p) )
        sum[p].insert({a.x,a.y});
}
//删除节点
void del(Point a){
    int p = N - a.y;
    for( ; p < N; p = fa(p) )
        sum[p].erase({a.x,a.y});
}
//查询节点
void query(Point a){
    pair<int,int> ans = {INF,INF};
    set<pair<int,int>>::iterator it;
    //对小于a.y每个管辖区间进行遍历并进行二分查找寻找最优解
    //为什么是小于a.y的,因为大于a.y肯定不符合条件嘛
    for( int i = N-a.y-1; i; i -= lowbit(i) ){	                        
        it = sum[i].lower_bound({a.x+1,a.y});
        if(it!=sum[i].end()) ans = min(ans,*it);
    }
    if(ans.first == INF && ans.second == INF) printf("-1\n");
    else printf("%lld %lld\n",ans.first,mp[ans.second]);
}
signed main(){
    //std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;
    scanf("%lld",&T);
    vector<Point> v;
    vector<char> op;
    vector<int> b;
    for (int i = 0; i < T; ++i) {
        string c;
        int x,y;
        Point a;
        cin>>c;
        scanf("%lld%lld",&x,&y);
        a.x = x; a.y = y;
        v.push_back(a);
        op.push_back(c[0]);
        b.push_back(a.y);
    }
    //离散化
    sort(b.begin(),b.end());
    int m = unique(b.begin(),b.end()) - b.begin();
    for (int i = 0; i < v.size(); ++i) {
        int pos = lower_bound(b.begin(),b.begin()+m,v[i].y) - b.begin();
        mp[pos] = v[i].y;
        v[i].y = pos;
    }
    for (int i = 0; i < T; ++i) {
        if(op[i] == 'a') add(v[i]);
        if(op[i] == 'r') del(v[i]);
        if(op[i] == 'f') query(v[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值