BZOJ4605 崂山白花蛇草水
定位:值域线段树 套 K-DTree
Problem
- 在坐标系上插入一个点\((x,y)\),\(w(x,y)=v\)
- 询问一个矩形内\(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;
}