Codeforces19 D. Points(线段树上二分+set)

题意:

有一个二维坐标系,q次操作,操作有三种:
(1,x,y)将点(x,y)加入集合
(2,x,y)将点(x,y)从集合中删除,保证删除合法
(3,x,y)查询严格在点(x,y)右上角的所有点中,横坐标最小的那个,如果横坐标相同则找纵坐标最小的

数据范围:q<=2e5,0<=坐标<=1e9,保证坐标两两不同

解法:

横坐标离散化,对横坐标开权值线段树
对于每个叶子维护一个set,存当前x的所有纵坐标y
添加删除就正常维护,查询就变为查询>x的所有横坐标中,纵坐标>y的所有点中,横坐标的最小的
优先找左子树就行了,多维护一个区间最值进行剪枝,如果不剪枝复杂度会退化(显然)。
找纵坐标>y中最小的可以用set自带的二分找,很快

ps:
这题cin关同步还是会比scanf慢1000+ms,差别有点大

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
struct Q{
    int op,x,y;
}q[maxm];
int a[maxm<<2],ma[maxm<<2];
multiset<int>s[maxm<<2];
int xx[maxm],num;
int n;
void update(int x,int val,int op,int l,int r,int node){
    if(l==r){
        if(op==1){//add
            s[node].insert(val);
            ma[node]=max(ma[node],val);
        }else{//del
            s[node].erase(val);
            if(!s[node].size()){
                ma[node]=0;
            }else{
                ma[node]=*s[node].rbegin();
            }
        }
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid)update(x,val,op,l,mid,node*2);
    else update(x,val,op,mid+1,r,node*2+1);
    ma[node]=max(ma[node*2],ma[node*2+1]);
}
pair<int,int> ask(int x,int val,int l,int r,int node){
    if(x>r)return {-1,-1};
    if(ma[node]<=val)return {-1,-1};
    if(l==r){
        int y=*s[node].upper_bound(val);
        return {xx[l],y};
    }
    int mid=(l+r)/2;
    if(x<=mid){
        pair<int,int>ans=ask(x,val,l,mid,node*2);
        if(ans.first!=-1)return ans;
    }
    return ask(x,val,mid+1,r,node*2+1);
}
signed main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        char s[10];scanf("%s",s);
        int x,y;scanf("%d%d",&x,&y);
        xx[++num]=x;
        if(s[0]=='a'){
            q[i]={1,x,y};
        }else if(s[0]=='r'){
            q[i]={2,x,y};
        }else if(s[0]=='f'){
            q[i]={3,x,y};
        }
    }
    //离散化
    sort(xx+1,xx+1+num);
    num=unique(xx+1,xx+1+num)-xx-1;
    for(int i=1;i<=n;i++){
        q[i].x=lower_bound(xx+1,xx+1+num,q[i].x)-xx;
    }
    //
    for(int i=1;i<=n;i++){
        if(q[i].op!=3){
            update(q[i].x,q[i].y,q[i].op,1,num,1);
        }else{
            pair<int,int>ans=ask(q[i].x+1,q[i].y,1,num,1);
            if(ans.first==-1){
                puts("-1");
            }else{
                printf("%d %d\n",ans.first,ans.second);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107478434