【线段树套KD树】[BZOJ4605]崂山白花蛇草水
来源:互联网 发布:highcharts zh cn.js 编辑:程序博客网 时间:2024/04/28 14:02
题目描述
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
Idea By Aleph, Description & Data cases By jinlifu1999.
分析
本题强制在线,显然是一道数据结构题,维护的是一个二维区间,想到树套树或者K-D树,还要寻找第k大,所以还需要再套一棵树。树套树套树编码难度和常数都很大,所以我们选择K-D树。另一棵树显然有很多种选择,但是显然线段树是我们最佳的选择,因为它的形态不会改变。由于K-D树随着节点的增加会变得不平衡,我们可以使用类似替罪羊树的重建方法对K-D树进行部分重构,如果放外层重建的时空开销会比较大。所以我们外层维护一棵权值线段树,内层维护一棵K-D树即可时间复杂度
代码
#include<cstdio>#include<algorithm>#include<queue>#include<vector>#define alpha 0.77#define MAXV 1000000000#define MAXN 100000using namespace std;int n,Q,ans;void Read(int &x){ char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; }}namespace K_DTree{int D;bool rbd;struct node{ int d[2],mn[2],mx[2],cnt,sum; node *ch[2]; inline node(){ } inline node(int x,int y):cnt(1){ d[0]=mn[0]=mx[0]=x,d[1]=mx[1]=mn[1]=y; } inline bool operator<(const node &b)const{ return d[D]<b.d[D]; } inline bool operator==(const node &b)const{ return d[0]==b.d[0]&&d[1]==b.d[1]; }}now,tree[MAXN*25+10],*tcnt=tree,*v[MAXN+10],**vcnt,**rbt;inline bool cmp(node *x,node *y){ return x->d[D]<y->d[D];}inline int Get_sum(node *p){ return p?p->sum:0;}inline bool in(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){ return x1<=X1&&X2<=x2&&y1<=Y1&&Y2<=y2;}inline bool out(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){ return x1>X2||x2<X1||y1>Y2||y2<Y1;}inline bool balance(node *p){ return p->sum*alpha>=max(Get_sum(p->ch[0]),Get_sum(p->ch[1]));}void update(node *p){ for(int i=0;i<2;i++){ p->mx[i]=p->mn[i]=p->d[i]; if(p->ch[0]) p->mn[i]=min(p->mn[i],p->ch[0]->mn[i]),p->mx[i]=max(p->mx[i],p->ch[0]->mx[i]); if(p->ch[1]) p->mn[i]=min(p->mn[i],p->ch[1]->mn[i]),p->mx[i]=max(p->mx[i],p->ch[1]->mx[i]); } p->sum=Get_sum(p->ch[0])+Get_sum(p->ch[1])+p->cnt;}void rebuild(node *&p,int l,int r,bool f){ if(l>r) return; D=f; int mid=(l+r)>>1; nth_element(v+l,v+mid,v+r+1,cmp); p=v[mid]; p->ch[0]=p->ch[1]=0; rebuild(p->ch[0],l,mid-1,f^1); rebuild(p->ch[1],mid+1,r,f^1); update(p);}void travel(node *p){ if(!p) return; *++vcnt=p; travel(p->ch[0]); travel(p->ch[1]);}void insert(node *&p,bool D){ if(!p){ p=++tcnt; p->cnt=p->sum=0; p->ch[0]=p->ch[1]=0; p->d[0]=p->mn[0]=p->mx[0]=now.d[0]; p->d[1]=p->mn[1]=p->mx[1]=now.d[1]; } if(*p==now){ p->sum++; p->cnt++; return; } if(now.d[D]<p->d[D]) insert(p->ch[0],D^1); else insert(p->ch[1],D^1); update(p); if(!balance(p)) rbt=&p,rbd=D;}void rebuild(node *&rt,bool f){ vcnt=v; travel(rt); rt=0; rebuild(rt,1,vcnt-v,f);}inline void insert(node *&rt){ rbt=0; insert(rt,0); if(rbt) rebuild(*rbt,rbd);}int get_sum(node *p,int x1,int y1,int x2,int y2){ if(!p) return 0; if(in(x1,y1,x2,y2,p->mn[0],p->mn[1],p->mx[0],p->mx[1])) return p->sum; if(out(x1,y1,x2,y2,p->mn[0],p->mn[1],p->mx[0],p->mx[1])) return 0; return get_sum(p->ch[0],x1,y1,x2,y2)+get_sum(p->ch[1],x1,y1,x2,y2)+p->cnt*in(x1,y1,x2,y2,p->d[0],p->d[1],p->d[0],p->d[1]);}}int x[MAXN+10],y[MAXN+10],val[MAXN+10];namespace SegmentTree{struct node{ K_DTree::node *root; node *ch[2];}tree[MAXN*20+10],*tcnt=tree,*nil=tree,*root=nil;inline void init(){ nil->ch[0]=nil->ch[1]=nil;}void insert(node *&p,int l,int r,int pos){ if(p==nil){ p=++tcnt; p->ch[0]=p->ch[1]=nil; } K_DTree::insert(p->root); if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) insert(p->ch[0],l,mid,pos); else insert(p->ch[1],mid+1,r,pos);}int Query(node *p,int l,int r,int x1,int y1,int x2,int y2,int k){ if(l==r) return l; int mid=(l+r)>>1,t; if((t=K_DTree::get_sum(p->ch[1]->root,x1,y1,x2,y2))>=k) return Query(p->ch[1],mid+1,r,x1,y1,x2,y2,k); return Query(p->ch[0],l,mid,x1,y1,x2,y2,k-t);}}using namespace SegmentTree;int main(){ init(); Read(n),Read(Q); int x,y,v,x1,y1,p; while(Q--){ Read(p); if(p==1){ Read(x),Read(y),Read(v); x^=ans,y^=ans,v^=ans; K_DTree::now=K_DTree::node(x,y); insert(root,1,MAXV,v); } else{ Read(x),Read(y),Read(x1),Read(y1),Read(v); x^=ans,y^=ans,x1^=ans,y1^=ans,v^=ans; if(K_DTree::get_sum(root->root,x,y,x1,y1)<v) puts("NAIVE!ORZzyz."),ans=0; else printf("%d\n",ans=Query(root,1,MAXV,x,y,x1,y1,v)); } }}
- 【线段树套KD树】[BZOJ4605]崂山白花蛇草水
- [BZOJ4605]崂山白花蛇草水(主席树套kd-tree)
- [权值线段树套kd树 替罪羊式重构] BZOJ 4605 崂山白花蛇草水
- [BZOJ]4605 崂山白花蛇草水 线段树套KD-Tree
- BZOJ 4605: 崂山白花蛇草水 树套树 权值线段树套kdtree
- bzoj4604 The kth maximum number && bzoj4605 崂山白花蛇草水
- BZOJ 4605 崂山白花蛇草水 权值线段树+K-D树
- [bzoj4605]崂山白花蛇草水 k-d tree 带替罪羊重构
- 崂山白花蛇草水:旧款变爆款老字号“有预谋”
- 线段树套Treap
- bzoj3196(线段树套treap)
- 【线段树套线段树】POJ2155 Matrix
- hdu4819 线段树套线段树
- uva11297 - Census 线段树套线段树
- POJ2155 线段树套线段树
- poj2155(线段树套线段树)
- BZOJ 3110 线段树套线段树
- 树套树-线段树套线段树
- flask-mail常见的邮箱配置问题解决
- HTML5
- 练习四图论1003
- my code
- Java NIO系列教程(一) Java NIO 概述
- 【线段树套KD树】[BZOJ4605]崂山白花蛇草水
- 视觉SLAM漫谈(一)
- tomcat 错误页面设置
- Java NIO系列教程(二) Channel
- 视觉SLAM漫谈(二):图优化理论与G2O的使用
- JavaScript检测原始值、引用值、属性
- 101个MySQL调试和优化技巧
- 横向滑动的HorizontalListView滑动指定位置的解决方法
- 8 个不得不说的 MySQL 陷阱