CodeForces 19D Points(离散化+线段树+单点更新)

题目链接:

huangjing

题意:给了三种操作

1:add(x,y)将这个点加入二维坐标系

2:remove(x,y)将这个点从二维坐标系移除。

3:find(x,y)就是找到在(x,y)右上方的第一个点。

思路:我们可以建立n个set以x为横坐标,那么我们这个题就转化为找一个最小的x是否存在满足条件,那么x一旦被找到,那么纵坐标就自然而然的找到了,当然更新操作就是对maxy的维护,然后查询操作就是找出一个最小的x。。还有因为n非常大,所以要采用离散化的方法,然后进行离线处理。还是就是掌握set的用法,看来得买本c++primer了。insert(int val)将val插入到set中,且保证有序,erase(int val)将val删除且保证有序。。

题目:

D. Points

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

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 test(s)

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

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#include<string>
#include<queue>
#define eps 1e-9
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=200000+10;
struct Tree
{
    int x,y;
    char op[5];
    void init()
    {
        scanf("%s%d%d",op,&x,&y);
    }
}tree[maxn<<2];

set<int>xx[maxn];
int maxy[maxn<<2],top[maxn],n,m;

void buildtree(int l,int r,int dex)
{
    maxy[dex]=-1;
    if(l==r) return;
    int mid=(l+r)>>1;
    buildtree(l,mid,dex<<1);
    buildtree(mid+1,r,dex<<1|1);
}

void update(int l,int r,int dex,int pos)
{
     if(l==r)
     {
         if(xx[pos].size())
            maxy[dex]=*(--xx[pos].end());
         else
            maxy[dex]=-1;
         return;
     }
     int mid=(l+r)>>1;
     if(pos<=mid)  update(l,mid,dex<<1,pos);
     else  update(mid+1,r,dex<<1|1,pos);
     maxy[dex]=max(maxy[dex<<1],maxy[dex<<1|1]);
}

int Query(int l,int r,int dex,int L,int R,int val)
{
   if(maxy[dex]<=val||L>R)  return -1;//这里L>R是一个trick,wa在了第4组数据,有可能L>R
   if(l==r) return l;
   int mid=(l+r)>>1;
   if(R<=mid)  return Query(l,mid,dex<<1,L,R,val);
   else if(L>mid)  return Query(mid+1,r,dex<<1|1,L,R,val);
   else
   {
       int t=Query(l,mid,dex<<1,L,R,val);
       if(t!=-1)  return t;
       return Query(mid+1,r,dex<<1|1,L,R,val);
   }
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            tree[i].init();
            top[i]=tree[i].x;
        }//离散化
        sort(top+1,top+1+n);
        m=unique(top+1,top+1+n)-(top+1);
        for(int i=1;i<=m;i++)
            xx[i].clear();
        buildtree(1,m,1);
        for(int i=1;i<=n;i++)
        {
             int pos=lower_bound(top+1,top+1+m,tree[i].x)-top;
             if(tree[i].op[0]=='a')
             {
                 xx[pos].insert(tree[i].y);
                 update(1,m,1,pos);
             }
             else if(tree[i].op[0]=='r')
             {
                 xx[pos].erase(tree[i].y);
                 update(1,m,1,pos);
             }
             else
             {
                int ans=Query(1,m,1,pos+1,m,tree[i].y);
                if(ans==-1)
                    printf("-1\n");
                else
                    printf("%d %d\n",top[ans],*xx[ans].upper_bound(tree[i].y));
             }
        }
    }
    return 0;
}
时间: 2024-11-10 07:33:34

CodeForces 19D Points(离散化+线段树+单点更新)的相关文章

CodeForces 19D Points(线段树+map)

开始想不通,后来看网上说是set,就有一个想法是对每个x建一个set...然后又想直接建立两重的set就好,最后发现不行,自己想多了...  题意是给你三种操作:add (x y) 平面添加(x y)这个点 remove (x y)平面删除(x y)这个点 find (x y) 查找(x y)这个点严格的右上方中最左边的点,有多个就再找最下方的点,输出 其实想通了还是比较简单的,我的想法就是对于x先排序再对y排序,这样建一颗线段树,用处在于:添加和删除都可以当成单点更新,只需要记录最大值就好.f

POJ2352_Stars(线段树/单点更新)

解题报告 题意: 坐标系中,求每颗星星的左下角有多少星星. 思路: 把横坐标看成区间,已知输入是先对y排序再对x排序,每次加一个点先查询该点x坐标的左端有多少点,再更新点. #include <iostream> #include <cstdio> #include <cstring> using namespace std; int sum[200000]; struct node { int x,y; } p[20000]; void push_up(int roo

Minimum Inversion Number(线段树单点更新+逆序数)

Minimum Inversion Number(线段树单点更新+逆序数) Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy

POJ训练计划2299_Ultra-QuickSort(线段树/单点更新)

解题报告 题意: 求逆序数. 思路: 线段树离散化处理. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; LL sum[2001000],num[501000],_hash[501000]; void push_up(int rt) { sum[rt]=sum[rt*2

POJ训练计划2828_Buy Tickets(线段树/单点更新)

解题报告 题意: 插队完的顺序. 思路: 倒着处理数据,第i个人占据第j=pos[i]+1个的空位. 线段树维护区间空位信息. #include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int x,v; } num[201000]; int sum[1000000],ans[201000]; void cbtree(int rt,int l,in

HDU2852_KiKi&#39;s K-Number(线段树/单点更新)

解题报告 题目传送门 题意: 意思很好理解. 思路: 每次操作是100000次,数据大小100000,又是多组输入.普通模拟肯定不行. 线段树结点记录区间里存在数字的个数,加点删点操作就让该点个数+1,判断x存在就查询[1,x]区间的个数和[1,x-1]的个数. 求x之后第k大的数就先确定小于x的个数t,第t+k小的数就是要求的. #include <iostream> #include <cstdio> #include <cstring> using namespa

POJ3264_Balanced Lineup(线段树/单点更新)

解题报告 题意: 求区间内最大值和最小值的差值. 思路: 裸线段树,我的线段树第一发.区间最值. #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 #define LL long long using namespace std; LL minn[201000],maxx[201000]; void update(LL root,LL l,LL r,LL p,LL

HDU1166_敌兵布阵(线段树/单点更新)

解题报告 题意: 略 思路: 线段树单点增减和区间求和. #include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; int sum[201000]; void update(int root,int l,int r,int p,int v) { int mid=(l+r)/2; if(l==r)sum[root]+=v; else

HDU1754_I Hate It(线段树/单点更新)

解题报告 题意: 略 思路: 单点替换,区间最值 #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 using namespace std; int maxx[808000]; void update(int root,int l,int r,int p,int v) { int mid=(l+r)/2; if(l==r)maxx[root]=v; else if(