codeforces 19D(線段樹端點維護set 或腦補CDQ?)

題意:二維平面三種操作,添加一個點,刪除一個點,詢問一個點的嚴格右上方中離他最近的點,若有多個則橫座標小的優先,操作次數21052*10^5,保證操作合法。

對橫座標離散化後,線段樹葉子節點建立set,存放y座標,那麼增與刪都很好做,同時線段樹維護y座標最大值,查詢的時候如果左右子樹同時都可能滿足,則優先查詢左子樹,若找不到答案再查右子樹,查詢過程中同時使用max進行搜索剪枝。

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
 
const int maxn=2e5+7;
 
set<int> s[maxn<<2|1];
 
int maxx[maxn<<2|1];
 
void build(int l,int r,int k){
    maxx[k]=-1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
}
 
void insert(int l,int r,int k,int id,int val){
    if(l==r){
        s[k].insert(val);
        maxx[k]=*(--s[k].end());
        return ;
    }
    int mid=(l+r)>>1;
    if(id<=mid) insert(l,mid,k<<1,id,val);
    else insert(mid+1,r,k<<1|1,id,val);
    maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
}
 
void erase(int l,int r,int k,int id,int val){
    if(l==r){
        s[k].erase(s[k].find(val));
        if(s[k].empty()) maxx[k]=-1;
        else maxx[k]=*(--s[k].end());
        return ;
    }
    int mid=(l+r)>>1;
    if(id<=mid) erase(l,mid,k<<1,id,val);
    else erase(mid+1,r,k<<1|1,id,val);
    maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
}
 
int res=-1;
int ask(int l,int r,int k,int id,int val){
    if(maxx[k]<val) return -1;
    if(l==r){
        if(s[k].empty()) return -1;
        set<int>::iterator it=s[k].upper_bound(val);
        if(it==s[k].end()) return -1;
        res=l;
        return (*it);
    }
    int mid=(l+r)>>1;
    if(id>mid) return ask(mid+1,r,k<<1|1,id,val);
    else{
        int hh=-1;
        hh=ask(l,mid,k<<1,id,val);
        if(hh!=-1) return hh;
        return ask(mid+1,r,k<<1|1,id,val);
    }
}
 
int b[maxn];
int m;
void quchong(int n){
    sort(b+1,b+1+n);
    m=unique(b+1,b+1+n)-b-1;
}
int getid(int x){ return lower_bound(b+1,b+1+m,x)-b; }
 
struct Node{
    int type; //0 add  1 erase 2 ask
    int x,y;
}a[maxn];
char ss[9];
int main(){
    int q,num=0;
    scanf("%d",&q);
    for(int i=1;i<=q;++i){
        scanf("%s%d%d",ss,&a[i].x,&a[i].y);
        b[i]=a[i].x;
        if(ss[0]=='a') a[i].type=0;
        else if(ss[0]=='r') a[i].type=1;
        else a[i].type=2;
    }
    quchong(q);
    b[++m]=b[m-1]+1;
    //for(int i=1;i<=m;++i) cout<<b[i]<<" ";cout<<endl;
    build(1,m,1);
    for(int i=1;i<=q;++i){
        if(a[i].type==0) insert(1,m,1,getid(a[i].x),a[i].y);
        else if(a[i].type==1) erase(1,m,1,getid(a[i].x),a[i].y);
        else{
            res=-1;
            int hh=ask(1,m,1,getid(a[i].x)+1,a[i].y);
            if(res==-1) printf("-1\n");
            else{
                printf("%d %d\n",b[res],hh);
            }
        }
    }
 
 
    return 0;
}

再來一種我自己yy的做法,現在還沒有調過去2333。
用CDQ將動態問題轉化爲靜態問題,三種操作,刪除優於添加,然後是查詢,按照x座標從大到小,y從大到小,同時樹狀數組維護y座標下的x+y最小,同時標記這個最小值的點的所屬。

寫完再更。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章