【崂山白花蛇草水】权值线段树套kd-tree
感觉自己过得十分地卡orz,大常数玩家瑟瑟发抖。
BZOJ4605
LUOGU4848
4605: 崂山白花蛇草水
Time Limit: 80 Sec Memory Limit: 512 MB Submit: 700 Solved: 218 [Submit][Status][Discuss]Description
神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水。凭借着神犇Aleph的实
力,他轻松地进了山东省省队,现在便是他履行诺言的时候了。蒟蒻Bob特地为他准备了999,999,999,999,999,999
瓶崂山白花蛇草水,想要灌神犇Aleph。神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bo
b最终答应了他的请求,但蒟蒻Bob决定将计就计,也让神犇Aleph回答一些问题。具体说来,蒟蒻Bob会在一个宽敞
的广场上放置一些崂山白花蛇草水(可视为二维平面上的一些整点),然后询问神犇Aleph在矩形区域(x1, y1), (
x2, y2)(x1≤x2且y1≤y2,包括边界)中,崂山白花蛇草水瓶数第k多的是多少。为了避免麻烦,蒟蒻Bob不会在同
一个位置放置两次或两次以上的崂山白花蛇草水,但蒟蒻Bob想为难一下神犇Aleph,希望他能在每次询问时立刻回
答出答案。神犇Aleph不屑于做这种问题,所以把这个问题交给了你。
Input
输入的第一行为两个正整数N, Q,表示横纵坐标的范围和蒟蒻Bob的操作次数(包括放置次数和询问次数)。
接下来Q行,每行代表蒟蒻Bob的一个操作,操作格式如下:
首先第一个数字type,表示操作种类。type=1表示放置,type=2表示询问。
若type=1,接下来会有三个正整数x, y, v,表示在坐标整点(x, y)放置v瓶崂山白花蛇草水。(1≤x, y≤N, 1≤v≤10^9)
若type=2,接下来会有五个正整数x1, y1, x2, y2, k,表示询问矩形区域(x1, y1), (x2, y2)中,崂山白花蛇草水瓶数第k多的是多少。
(1≤x1≤x2≤N,1≤y1≤y2≤N,1≤k≤Q)
为了体现程序的在线性,你需要将每次读入的数据(除了type值)都异或lastans,其中lastans表示上次询问的答
案。如果上次询问的答案为"NAIVE!ORZzyz."(见样例输出),则将lastans置为0。初始时的lastans为0。
初始时平面上不存在崂山白花蛇草水。
本题共有12组测试数据。对于所有的数据,N≤500,000。
Q的范围见下表:
测试点1-2 Q=1,000
测试点3-7 Q=50,000
测试点8-12 Q=100,000
Output
对于每个询问(type=2的操作),回答崂山白花蛇草水瓶数第k多的是多少。若不存在第k多的瓶数,
请输出"NAIVE!ORZzyz."(输出不含双引号)。
Sample Input
10 7
1 1 1 1
1 2 2 3
1 4 1 2
1 3 4 4
2 1 1 4 1 3
2 2 2 3 5 4
2 2 1 4 4 2
Sample Output
NAIVE!ORZzyz.
NAIVE!ORZzyz.
3
HINT
Source
乍一眼看到这道题,由于刚做了K远点对,第一个想法是大小根堆A*乱搞一下,看了下K的范围orz。 好吧。我们发现求第K大的那个点的瓶数,这个我们可以想到主席树。所以说理论上外层套一个KD-TREE内层一个树上主席树,每次主席树提出log个点来搞应该是可以的。但是我们很容易发现他的常数有点爆炸,因为最关键的内层树时间复杂度总要跑满。那么我们可以换一下想法,外层套一个权值线段树,维护所有权值在区间点的KD-TREE,这样我们查询的时候看一下线段树右儿子的KD-TREE被包含是否有k个递归到右边,否则递归到左边,利用kd-tree判一下矩形是否有交和矩形是否覆盖既可。 code:// luogu-judger-enable-o2 #include<stdio.h> #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> using namespace std; const int maxn = 100005; const int inf = 1e9; int n,q; struct node{ node *ls,*rs; int siz; int sx[2],sy[2]; int x,y; }z[maxn*40],*tl,*nul,**RT,*pool[maxn]; int lj; bool isbad(node *&p) { if(max(p->ls->siz,p->rs->siz)*4>p->siz*3) return 1; return 0; } struct orz{ int xx,yy; }sta[maxn]; int top; void upd(node *&p) { p->siz=1; if(p->ls!=nul) { p->sx[0] = min(p->sx[0],p->ls->sx[0]); p->sx[1] = max(p->sx[1],p->ls->sx[1]); p->sy[0] = min(p->sy[0],p->ls->sy[0]); p->sy[1] = max(p->sy[1],p->ls->sy[1]); p->siz+=p->ls->siz; } if(p->rs!=nul) { p->sx[0] = min(p->sx[0],p->rs->sx[0]); p->sx[1] = max(p->sx[1],p->rs->sx[1]); p->sy[0] = min(p->sy[0],p->rs->sy[0]); p->sy[1] = max(p->sy[1],p->rs->sy[1]); p->siz+=p->rs->siz; } } node* nwnode(int x,int y) { node* p = lj?pool[lj--]:++tl; p->ls = p->rs = nul; p->siz = 1; p->sx[0] = p->sx[1] = p->x = x; p->sy[0] = p->sy[1] = p->y = y; return p; } void tra(node *&p) { if(p==nul)return; tra(p->ls); pool[++lj] = p; ++top; sta[top].xx= p->x; sta[top].yy = p->y; tra(p->rs); } bool cmpx(orz aa,orz bb) { return aa.xx < bb.xx ; } bool cmpy(orz aa,orz bb) { return aa.yy < bb.yy; } void build(node *&p,int l,int r,int nw) { int mid = (l+r)>>1; if(!nw) nth_element(sta+l,sta+mid,sta+r+1,cmpx); else nth_element(sta+l,sta+mid,sta+r+1,cmpy); p = nwnode(sta[mid].xx,sta[mid].yy); if(l<mid) build(p->ls,l,mid-1,nw^1); if(mid<r) build(p->rs,mid+1,r,nw^1); upd(p); } void rebuild() { if(*RT==nul) return; top = 0; tra(*RT); if(top>0) build(*RT,1,top,0); else *RT = nul; RT = &nul; } int XA,YA,XB,YB,VV; void inskd(node *&p,int nw) { if(p==nul) { p = nwnode(XA,YA); return; } if(nw==0) { XA<=p->x?inskd(p->ls,nw^1):inskd(p->rs,nw^1); } else { YA<=p->y?inskd(p->ls,nw^1):inskd(p->rs,nw^1); } upd(p); if(isbad(p)) RT = &p; } bool panj(node *&p) { int xo1 = max(p->sx[0],XA); int yo1 = min(p->sy[1],YB); int xo2 = min(p->sx[1],XB); int yo2 = max(p->sy[0],YA); if(xo1<=xo2&&yo2<=yo1) return 1; return 0; } bool baohan(node *&p) { if(XA<=p->sx[0]&&p->sx[1]<=XB&&YA<=p->sy[0]&&p->sy[1]<=YB) return 1; return 0; } bool dianh(node *&p) { if(XA<=p->x&&p->x<=XB&&YA<=p->y&&p->y<=YB) return 1; return 0; } int kdquery(node *&p) { if(p==nul||p==NULL) return 0; if(!panj(p)) return 0; if(baohan(p)) return p->siz; return kdquery(p->ls) + kdquery(p->rs) + dianh(p); } struct nod{ int ls,rs; node *rt; }dt[maxn*40]; int tot; int rrt; void init() { tl = nul = z; nul->ls = nul->rs = nul; rrt = ++tot; dt[rrt].rt = nul; RT = &nul; } void zxins(int &p,int l,int r) { if(!p) { p = ++tot; dt[p].rt = nul; } inskd(dt[p].rt,0); if(*RT!=nul) rebuild(); if(l==r) return; int mid = (l+r)>>1; if(VV<=mid) zxins(dt[p].ls,l,mid); else zxins(dt[p].rs,mid+1,r); } int query(int &p,int l,int r,int k) { if(!p) { p = ++tot; dt[p].rt = nul; } if(l==r) return l; int mid = (l+r)>>1; int rsz = dt[p].rs ? kdquery(dt[dt[p].rs].rt) : 0; if(rsz>=k) return query(dt[p].rs,mid+1,r,k); else return query(dt[p].ls,l,mid,k-rsz); } int main() { init(); scanf("%d%d",&n,&q); int type,k; int lastans = 0; for(int i=1;i<=q;i++) { scanf("%d",&type); if(type==1) { scanf("%d%d%d",&XA,&YA,&VV); XA^=lastans; YA^=lastans; VV^=lastans; zxins(rrt,1,inf); } else { scanf("%d%d%d%d%d",&XA,&YA,&XB,&YB,&k); XA^=lastans; YA^=lastans; XB^=lastans; YB^=lastans; k^=lastans; if(XA>XB) swap(XA,XB); if(YA>YB) swap(YA,YB); if( kdquery(dt[rrt].rt ) <k ) puts("NAIVE!ORZzyz."),lastans=0; else { lastans = query(rrt,1,inf,k); printf("%d\n",lastans); } } } }