CF19D 线段树+STL各种应用

http://codeforces.com/problemset/problem/19/D

Description

Pete and Bob invented a new interesting game. Bob takes a sheet of paper and locates a Cartesian coordinate system on it as follows: point (0,?0) is located in the bottom-left corner, Ox axis
is directed right, Oy axis is directed up. Pete gives Bob requests of three types:

  • add x y — on the sheet of paper Bob marks a point with coordinates (x,?y). For each request of this type it‘s guaranteed that point(x,?y) is
    not yet marked on Bob‘s sheet at the time of the request.
  • remove x y — on the sheet of paper Bob erases the previously marked point with coordinates (x,?y). For each request of this type it‘s guaranteed
    that point (x,?y) is already marked on Bob‘s sheet at the time of the request.
  • find x y — on the sheet of paper Bob finds all the marked points, lying strictly above and strictly to the right of point (x,?y). Among these points
    Bob chooses the leftmost one, if it is not unique, he chooses the bottommost one, and gives its coordinates to Pete.

Bob managed to answer the requests, when they were 10, 100 or 1000, but when their amount grew up to 2·105, Bob failed to cope. Now he needs a program that will answer all
Pete‘s requests. Help Bob, please!

Input

The first input line contains number n (1?≤?n?≤?2·105) — amount of requests. Then there follow n lines
— descriptions of the requests.add x y describes the request to add a point, remove x y — the request to erase a point, find x y — the request
to find the bottom-left point. All the coordinates in the input file are non-negative and don‘t exceed 109.

Output

For each request of type find x y output in a separate line the answer to it — coordinates of the bottommost among the leftmost marked points, lying strictly above and to the right of point (x,?y).
If there are no points strictly above and to the right of point (x,?y), output -1.

Sample Input

Input

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

Output

1 1
3 4
1 1

Input

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

Output

7 7
-1
5 5
/**
CF 19D 线段树+STL
题目大意:在平面直角坐标系的第一象限里进行一系列的点的删除,添加,查询操作。查询是返回(x,y)有上方最靠左最靠下的点的坐标,若不存在返回-1
解题思路:主要有利用线段树的单点更新和单点查询,对于所有x横坐标相同的点放入一个set中,确定了x之后直接upper_bound就是对应点的纵坐标
*/
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int maxn=200005;

struct note
{
    int mark,x,y;
} e[maxn];

int n,num[maxn];
char a[10];
set <int>s[maxn];

struct node
{
    int l,r;
    int max_y;
} tree[4*maxn];

void push_up(int root)
{
    tree[root].max_y=max(tree[root<<1].max_y,tree[root<<1|1].max_y);
}
void build(int l,int r,int root)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].max_y=-1;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
}

void update(int x,int root)
{
    if(x==tree[root].l&&x==tree[root].r)
    {
        if(s[x].size())
            tree[root].max_y=*(--s[x].end());
        else tree[root].max_y=-1;
        return;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(x<=mid)
        update(x,root<<1);
    else
        update(x,root<<1|1);
    push_up(root);
}

int query( int x,int y,int root )
{
    if(tree[root].r<=x)
        return -1;
    if(tree[root].max_y<=y)
        return -1;
    if(tree[root].l==tree[root].r)
        return tree[root].l;
    int t=query(x,y,root<<1);
    if(t==-1)
        t=query(x,y,root<<1|1);
    return t;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%s%d%d",a,&e[i].x,&e[i].y);
            if(a[0]=='a')
                e[i].mark=1;
            else if(a[0]=='r')
                e[i].mark=2;
            else
                e[i].mark=3;
            s[i].clear();
            num[i]=e[i].x;
        }
        sort(num+1,num+1+n);
        int m = unique(num+1 , num+1+n)-(num+1);///去重,返回最后一个有效点的下一个迭代器的地址
        build(1,m,1);
        for(int i=1; i<=n; i++)
        {
            int x=upper_bound(num+1,num+1+m,e[i].x)-(num+1);
            int y=e[i].y;
            if(e[i].mark==1)
            {
                s[x].insert(y);
                update(x,1);
            }
            else if(e[i].mark==2)
            {
                s[x].erase(y);
                update(x,1);
            }
            else
            {
                int ans=query(x,y,1);
                if(ans==-1)
                    puts("-1");
                else
                {
                    printf("%d %d\n",num[ans],*s[ans].upper_bound(y));
                }
            }
        }
    }
    return 0;
}
时间: 2024-10-11 00:09:19

CF19D 线段树+STL各种应用的相关文章

【BZOJ-4631】踩气球 线段树 + STL

4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 224  Solved: 114[Submit][Status][Discuss] Description 六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球. SHUXK 要进行Q次操作,每次从某一个盒子里拿出一个没被踩爆的气球,然后熊孩子们就会立刻把它踩爆. 这M个熊孩子每个人都指定了一个盒子区间[Li, R

hdu 5338 线段树+stl+贪心

下午比赛的时候写搓了,晚上重写一次就过了,o(╯□╰)o. 思路:按照字典序贪心,用线段树来维护区间最值,用set来维护求出答案的封闭区间. 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 #include <set> 7 using namespace std; 8 9

poj 2892 stl或线段树

标准解法应该是线段树,这里提供另一种思路:将“断点”(即被摧毁的村庄)放入stl的容器(我用的是set)中维护,对于每次查询,只要找这个数在哪两个断点之间即可,写起来轻松愉快. PS:hdu上的数据略坑,同一个村庄可以被摧毁多次,恢复的时候一次恢复就可以让它不再是断点,但是第一次恢复以后剩下几次也是需要恢复的...所以不能把它被摧毁的记录删除,另外没有被摧毁的村庄时也有R操作.poj上的数据比较规范,符合实际情况,没有上面的奇怪数据. 1 #include <algorithm> 2 #inc

hdu4288 Coder(线段树+离散化)

题目链接: huangjing 题意: 题目中给了三个操作 1:add x 就是把x插进去 2:delete x 就是把x删除 3:sum 就是求下标%5=3的元素的和. 还有一个条件是插入和删除最后都要保证数列有序... 首先告诉一种暴力的写法..因为时间非常充足,需要对stl里面的函数有所了解.. 就是直接申明一个vector的容器,然后直接用vector里面的操作比如 insert,erase等等操作..不过这个效率很低.. 最后跑出来6000多ms..(强哥的代码) 代码: #inclu

HDU 5371 Hotaru&#39;s problem manacher+(线段树or set)

题意,给定一个100000 的串,求他一个子串,使得将子串分成三部分有后,第一部分=第三部分,第一部分与第二部分对称(回文) 首先我们需要处理出以i为轴的回文串的两端,这个事情可以用Manacher算法完成,复杂度O(n) http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/ 这个博客写的很好懂.不会的童鞋可以去学习一下这个算法,非常精妙. 好的现在我们已经会了这个算法,并获得了每个点为轴的串的右端点p[i] 很简单地可以处理出左端

ACM学习历程——POJ3321 Apple Tree(搜索,线段树)

      Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by bran

[BZOJ1835][ZJOI2010]base 基站选址(DP+线段树)

首先想到DP,f[i][j]表示前i个村庄,共建了j个站的最小费用,且第j个站建在第i个村庄上 f[i][j]=min(f[i][j],f[k][j-1]+cost(k,i));(1<=k<i) cost(k,i)表示选了k和i之后,他们之间需要的w的和 然后这样是O(kn^2)的,对于100%的数据会T.我们可以发现瓶颈在于找到min(f[k][j-1]+cost(k,i)),考虑如何优化它.还有显然的是可以舍掉第二维,只要先枚举建的站的数量即可. 当i变为i+1时,对于那些原来能建立了i而

【线段树】bzoj3922 Karin的弹幕

设置一个值K. d<=K:建立多组线段树:d>K:暴力. 最优时间复杂度的伪计算: O(n*K*logn(建树)+m*logn(询问类型1)+m*n/K(询问类型2)+m*K*logn(修改)). 求此函数最小值,易得,当K=sqrt(m/logn)时, 时间复杂度:O(m*sqrt(m*logn)). 空间复杂度:O(n*sqrt(m/logn)). 当然,这个计算显然不完全合理,而且,由于使用STL的vector的原因,导致实际建树要慢得多,因此K取得小一些更加合适(跑几组数据自己看看就行

可持续化线段树(主席树)

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的