[BZOJ4605] 崂山白花蛇草水 题解

突然想买一瓶,然后喝上几口。(不要命的想法)


动态全局 \(k\) 大想到权值线段树上二分。

由于要存储二维的点,所以得用到我们神通广大的 \(KDT\) 了。

那么想到权值线段树套 \(KDT\) 这种算法了。

笔者用的是二进制分组的写法,插入单次均摊时间复杂度是 \(O(\log^3n)\),查询单次均摊时间复杂度是 \(O(\sqrt n\log n)\)

时间复杂度 \(O(n+q(\log^3n+\sqrt n\log n))\)

#include<bits/stdc++.h>
#define ls(x) nd[x].ls
#define rs(x) nd[x].rs
#define sm(x) nd[x].sm
#define id(x,y) nd[x].id[y]
#define lp(x,y) nd[x].lp[y]
#define rd(x,y) nd[x].rd[y]
#define mn(x,y,z) x<y?x<z?x:z:y<z?y:z
#define mx(x,y,z) x>y?x>z?x:z:y>z?y:z
#define mxx(x,y) x>y?x:y
using namespace std;
const int N=3e6+5;
struct node{
	int ls,rs,sm,id[2];
	int lp[2],rd[2];
}nd[N];int n,q,tot,a[N],la,kw;
int cmp(int x,int y){
	return id(x,kw)<id(y,kw);
}struct kd_tree{
	int rt[20],tp;
	void push_up(int x){
		sm(x)=sm(ls(x))+sm(rs(x))+1;
		lp(x,0)=mn(id(x,0),lp(ls(x),0),lp(rs(x),0));
		lp(x,1)=mn(id(x,1),lp(ls(x),1),lp(rs(x),1));
		rd(x,0)=mx(id(x,0),rd(ls(x),0),rd(rs(x),0));
		rd(x,1)=mx(id(x,1),rd(ls(x),1),rd(rs(x),1));
	}int build(int l,int r,int k){
		int mid=(l+r)/2;kw=k;
		nth_element(a+l,a+mid,a+r+1,cmp);
		if(l<mid) ls(a[mid])=build(l,mid-1,k^1);
		if(r>mid) rs(a[mid])=build(mid+1,r,k^1);
		return push_up(a[mid]),a[mid];
	}void clear(int &x){
		a[++tp]=x;
		if(ls(x)) clear(ls(x));
		if(rs(x)) clear(rs(x));x=0;
	}void add(int x){
		a[tp=1]=x;int t=0;
		while(rt[t]) clear(rt[t]),t++;
		rt[t]=build(1,tp,0);
	}void insert(int x,int y){
		id(++tot,0)=x,id(tot,1)=y,add(tot);
	}void que(int x,int xa,int ya,int xb,int yb,int k,int &s){
		if(lp(x,0)>=xa) if(rd(x,0)<=xb)
			if(lp(x,1)>=ya) if(rd(x,1)<=yb){
				s=mxx(0,s-sm(x));return;
		}if(lp(x,0)>xb) return;if(rd(x,0)<xa) return;
		if(lp(x,1)>yb) return;if(rd(x,1)<ya) return;
		if(id(x,0)>=xa) if(id(x,0)<=xb)
			if(id(x,1)>=ya) if(id(x,1)<=yb) s--;
		if(!s) return;
		if(ls(x)) que(ls(x),xa,ya,xb,yb,k^1,s);
		if(!s) return;
		if(rs(x)) que(rs(x),xa,ya,xb,yb,k^1,s);
	}int qu(int xa,int ya,int xb,int yb,int k){
		int t=20;
		while(t--) if(rt[t]){
			que(rt[t],xa,ya,xb,yb,0,k);
			if(!k) return 0;
		}return k;
	}
}tg[N];int cnt,lc[N],rc[N],rt;
void add(int &x,int l,int r,int k,int xc,int yc){
	if(!x) x=++cnt;tg[x].insert(xc,yc);
	if(l==r) return;int mid=(l+r)/2;
	if(k<=mid) add(lc[x],l,mid,k,xc,yc);
	else add(rc[x],mid+1,r,k,xc,yc);
}int ans(int x,int l,int r,int xa,int ya,int xb,int yb,int k){
	if(l==r) return l;int mid=(l+r)/2;
	int cc=tg[rc[x]].qu(xa,ya,xb,yb,k);
	if(cc) return ans(lc[x],l,mid,xa,ya,xb,yb,cc);
	return ans(rc[x],mid+1,r,xa,ya,xb,yb,k);
}int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>q,lp(0,0)=lp(0,1)=2e9;
	while(q--){
		int opt,x,y,z,w,k;
		cin>>opt>>x>>y>>z;
		x^=la,y^=la,z^=la;
		if(opt==2){
			cin>>w>>k,w^=la,k^=la;
			if(tg[rt].qu(x,y,z,w,k)){
				cout<<"NAIVE!ORZzyz.\n";
				la=0;continue;
			}la=ans(rt,1,1e9,x,y,z,w,k);
			if(!la) cout<<"NAIVE!ORZzyz.\n";
			else cout<<la<<"\n";
		}else add(rt,1,1e9,z,x,y);
	}return 0;
}
posted @ 2024-12-29 14:58  长安一片月_22  阅读(5)  评论(0编辑  收藏  举报