Codeforces Beta Round #19D 线段树

题意:

在一个二维平面内,现在有三个操作

add x y 向这个平面内添加一个点并且保证这个点之前没有被加入

remove x y 从这平面内删除这个点并且保证这个点时存在过的

find x y 找到这个点的右上角离它最近的那个点

思路:

二维转一维,以x轴作为线段树的区间,线段树每个区间保存这个区间最大的y,根节点用set保存有多少个y,因为只有20W个数然而数据大小达到10^9,所以还是要经过离散化,这题的离散化和 CF 85D 这题类似。当add进来时,只需要向叶子节点更新y,(记住叶子节点有set),remove操作只需要到达该叶子节点,删除对应的y值就可以了。find里面如果能找到叶子节点就代表着有值,此时就可以直接输出。具体见代码。

#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define Lchild rt<<1,L,m
#define Rchild rt<<1|1,m+1,R
#define maxn 200100
#define MAX(a,b) a>b?a:b
set<int>valu[maxn];
int size;
set<int>S;
map<int, int>mymap;
struct node
{
    int x, y;
};
node point[maxn];
int tree[maxn * 4];
int val[maxn];
void update(int x, int y, int flag, int rt = 1, int L = 1, int R = size)
{
    if (flag)
        tree[rt] = tree[rt] > y ? tree[rt] : y;
    if (L == R)
    {
        if (flag == 1)
            valu[x].insert(y);
        else
        {
            valu[x].erase(y);
            tree[rt] = valu[x].empty() ? -1 : *(--valu[x].end());
        }
        return;
    }
    int m = (L + R) >> 1;
    if (x <= m)
        update(x, y, flag, Lchild);
    else
        update(x, y, flag, Rchild);
    tree[rt] = MAX(tree[rt << 1], tree[rt << 1 | 1]);
}
char p[maxn];
bool findans(int x,int y,int rt=1,int L=1,int R=size)
{
    if (tree[rt] < y || R < x)
    {
        return false;
    }
    if (L == R)
    {
        printf("%d %d\n", val[L], *valu[L].lower_bound(y) - 1);
        //cout <<val[L]<< " " << *valu[L].lower_bound(y)-1<<endl;
        return true;
    }
    int m = (L + R) >> 1;
    bool ans = findans(x, y, Lchild);
    if (ans)
        return ans;
    return findans(x, y, Rchild);
}
int main()
{
    int N;
    cin >> N;
    string stemp;
    for (int i = 1; i <= N; i++)
    {
        cin >> stemp;
        p[i] = stemp[0];
        scanf_s("%d%d", &(point[i].x), &(point[i].y));
        S.insert(point[i].x);
    }
    vector<int>P(S.begin(), S.end());
    size = P.size();
    for (int i = 1; i <= N * 3; i++)
        tree[i] = -1;
    for (int i = 1; i <= size; i++)
    {
        val[i] = P[i - 1];
        mymap[P[i - 1]] = i;
    }
    for (int i = 1; i <= N; i++)
    {
        if (p[i] == 'a')
            update(mymap[point[i].x], point[i].y+1, 1);
        else if (p[i] == 'r')
            update(mymap[point[i].x], point[i].y + 1, -1);
        else
        {
            if (!findans(mymap[point[i].x] + 1, point[i].y + 2))
                puts("-1");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值