BZOJ4605 崂山白花蛇草水

定位:值域线段树 套 K-DTree

Problem

loj传送门 luogu传送门
两种操作:

  1. 在坐标系上插入一个点\((x,y)\)\(w(x,y)=v\)
  2. 询问一个矩形内\(w\)权值第\(k\)大是多少

强制在线

Solution

发现1,2操作在\(KDTree\)上实现非常容易,但是每个点有权值,且询问第\(k\)大貌似在\(KDTree\)不是很好搞。
但是第\(k\)大问题,可以通过其他数据结构,平衡树,值域线段树等实现。

于是,我们可以用值域线段树处理第\(k\)大,\(KDTree\)维护矩阵信息。

具体来说,就是树套树,外层值域线段树,内层\(KDTree\),对值域线段树每个值域在\(KDTree\)去维护在此值域上的点的个数。

在具体一点,就是值域线段树上\([l,r]\)区间内\(KDTree\)维护\(w(x,y) \in [l,r]\)的点的个数。
于是就可以再线段树上面进行第\(k\)大的查询。

\(code:\) 有点卡常

#include<bits/stdc++.h>

using namespace std;

#define baoyifanakioi "NAIVE!ORZzyz."
#define alpha 0.8

#define umin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define umax(a,b) ((a) = (a) > (b) ? (a) : (b))

const int inf = 1000000000;
const int MAX_N = 1000000 + 5;
const int MAX_D = 2;

int n,m,D,lastans,cnt;

struct Point{
    int x[MAX_D];
    inline bool operator < (const Point &p) const{
        return x[D]<p.x[D];
    }
};

int totKD;
struct KDnode{
    Point p,mx,mn;
    int ls,rs,sz;
}kdt[MAX_N<<2];

int totSG;
struct SegmentNode{
    int ls,rs,kdt_rt;
}sgt[MAX_N<<2];

inline void pushup(int p){
    for(int i=0;i<MAX_D;++i){
        kdt[p].mn.x[i]=kdt[p].mx.x[i]=kdt[p].p.x[i];
        if(kdt[p].ls) umin(kdt[p].mn.x[i],kdt[kdt[p].ls].mn.x[i]),umax(kdt[p].mx.x[i],kdt[kdt[p].ls].mx.x[i]);
        if(kdt[p].rs) umax(kdt[p].mx.x[i],kdt[kdt[p].rs].mx.x[i]),umin(kdt[p].mn.x[i],kdt[kdt[p].rs].mn.x[i]);
    }
    kdt[p].sz=kdt[kdt[p].ls].sz+kdt[kdt[p].rs].sz+1;
}

int a[MAX_N<<2],tot;

inline void pia(int x){
    a[++tot]=x;
    if(kdt[x].ls) pia(kdt[x].ls);
    if(kdt[x].rs) pia(kdt[x].rs);
}

inline bool cmp(int a,int b){
    return kdt[a].p<kdt[b].p;
}

int rebuild(int l,int r,int d){
    if(l>r) return 0;
    int mid=l+r>>1;
    D=d;
    nth_element(a+l,a+mid,a+1+r,cmp);
    int p=a[mid];
    kdt[p].ls=rebuild(l,mid-1,d^1);
    kdt[p].rs=rebuild(mid+1,r,d^1);
    pushup(p);
    return p;
}

inline bool check(int x){
    return max(kdt[kdt[x].ls].sz,kdt[kdt[x].rs].sz)>alpha*kdt[x].sz;
}

inline int rebuild(int x,int d){
    tot=0;
    pia(x);
    return rebuild(1,tot,d);
}

void KDTree_insert(int &p,int d,Point tmp){
    if(!p){
        p=++totKD;
        kdt[p].sz=1;
        kdt[p].p=kdt[p].mn=kdt[p].mx=tmp;
        return;
    }
    if(tmp.x[d]<kdt[p].p.x[d]) KDTree_insert(kdt[p].ls,d^1,tmp);
    else KDTree_insert(kdt[p].rs,d^1,tmp);
    pushup(p);
    if(check(p)) p=rebuild(p,d);
}

int KDTree_query(int x,Point ld,Point ru){
    int res=0;
    if(!x || kdt[x].mx.x[0]<ld.x[0] || kdt[x].mx.x[1]<ld.x[1] || kdt[x].mn.x[0]>ru.x[0] || kdt[x].mn.x[1]>ru.x[1]) return 0;
    if(ld.x[0]<=kdt[x].mn.x[0] && ld.x[1]<=kdt[x].mn.x[1] && kdt[x].mx.x[0]<=ru.x[0] && kdt[x].mx.x[1]<=ru.x[1]) return kdt[x].sz;
    if(ld.x[0]<=kdt[x].p.x[0] && ld.x[1]<=kdt[x].p.x[1] && kdt[x].p.x[0]<=ru.x[0] && kdt[x].p.x[1]<=ru.x[1]) res++;
    return res+KDTree_query(kdt[x].ls,ld,ru)+KDTree_query(kdt[x].rs,ld,ru);
}

void SegmentTree_modify(int &p,int l,int r,int x,Point tmp){
    if(!p) p=++totSG;
    KDTree_insert(sgt[p].kdt_rt,0,tmp);
    if(l==r) return;
    int mid=l+r>>1;
    if(x<=mid) SegmentTree_modify(sgt[p].ls,l,mid,x,tmp);
    else SegmentTree_modify(sgt[p].rs,mid+1,r,x,tmp);
}

int SegmentTree_query_kth(int p,int l,int r,int k,Point ld,Point ru){
    if(l==r) return l;
    int mid=l+r>>1;
    int t=KDTree_query(sgt[sgt[p].rs].kdt_rt,ld,ru);
    if(k<=t) return SegmentTree_query_kth(sgt[p].rs,mid+1,r,k,ld,ru);
    else return SegmentTree_query_kth(sgt[p].ls,l,mid,k-t,ld,ru);
}

int main(){
//    freopen("data10.in","r",stdin);
//    freopen("my-1.out","w",stdout);
    int root=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int type;
        scanf("%d",&type);  
        if(type==1){
            Point a;
            int v;
            scanf("%d%d%d",&a.x[0],&a.x[1],&v);
            a.x[0]^=lastans,a.x[1]^=lastans,v^=lastans;
            SegmentTree_modify(root,0,1000000000,v,a);
        }
        else{
            Point ld,ru;
            int k;
            scanf("%d%d%d%d%d",&ld.x[0],&ld.x[1],&ru.x[0],&ru.x[1],&k);
            ld.x[0]^=lastans,ld.x[1]^=lastans,ru.x[0]^=lastans,ru.x[1]^=lastans,k^=lastans;
            lastans=SegmentTree_query_kth(root,0,1000000000,k,ld,ru);
            if(!lastans) puts(baoyifanakioi);
            else printf("%d\n",lastans);
        }
    }
    return 0;
}
posted @ 2022-03-24 14:56  Thermalrays  阅读(43)  评论(2编辑  收藏  举报