BZOJ 4605 崂山白花蛇草水 权值线段树+K-D树
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
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
麻麻我树套树一A辣!!
NAIVE!ORZzyz.
3
这题一看就是树套树的裸题啊
首先要查k小值,那么就要在外面来颗权值线段树,然后像主席树查询一样查询,那么就需要排名,排名是矩形里的点的个数,用K-D树维护一下就好了!。
代码略长
#include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using std::min; using std::max; using std::nth_element; const double alpha = 0.755; const int MAXN = 100005; const int inf = 1000000000; int now,x0,x1,y0,y1,len,Ans,n,Q; template<typename _t> inline _t read(){ _t x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-f; for(;isdigit(ch);ch=getchar())x=x*10+(ch^48); return x*f; } struct Point{ int d[2]; inline int& operator [](int x){return d[x];} inline bool operator < (const Point &a)const{ return d[now]==a.d[now]?d[now^1]<a.d[now^1]:d[now]<a.d[now]; } }pt[MAXN]; struct node{ node *ls,*rs; Point point; int mn[2],mx[2],s,split; inline void Update(node *p){ if(!p)return; for(int i=0;i<=1;i++)mn[i]=min(mn[i],p->mn[i]); for(int i=0;i<=1;i++)mx[i]=max(mx[i],p->mx[i]); } inline void Maintain(){ s=1;mn[0]=mx[0]=point[0];mn[1]=mx[1]=point[1]; if(ls)s+=ls->s,Update(ls); if(rs)s+=rs->s,Update(rs); } inline bool in(int x0,int y0,int x1,int y1){ return x0<=mn[0] && x1>=mx[0] && y0<=mn[1] && y1>=mx[1]; } inline bool out(int x0,int y0,int x1,int y1){ return mn[0]>x1 || mx[0]<x0 || mn[1]>y1 || mx[1]<y0; } inline bool self(int x0,int y0,int x1,int y1){ return point[0]>=x0 && point[0]<=x1 && point[1]>=y0 && point[1]<=y1; } node(Point x,int sp){ split = sp; ls = rs= NULL; point = x;s=1; mn[0]=mx[0]=x[0]; mn[1]=mx[1]=x[1]; } node(){} void* operator new(size_t); void operator delete(void *p); #define size(x) ((x)?(x)->s:(0)) inline bool bad(){return size(ls)>=s*alpha||size(rs)>=s*alpha;} }*C,*mempool,*need; std::vector<node*>bin; void build(node *&o,int l,int r,int d=0){ if(l>r){o=NULL;return;} now = d;int mid = l+r>>1; nth_element(&pt[l],&pt[mid],&pt[r+1]); o = new node(pt[mid],now); build(o->ls,l,mid-1,d^1); build(o->rs,mid+1,r,d^1); o->Maintain(); } void* node :: operator new(size_t){ node *p; if(!bin.empty()){ p = bin.back(); bin.pop_back(); } else{ if(C==mempool){ C=new node[1<<15]; mempool=C+(1<<15); } p=C++; } return p; } void node::operator delete(void* p){ bin.push_back((node*)p); } int Query(node *o){ if(!o)return 0; if(o->in(x0,y0,x1,y1))return o->s; if(o->out(x0,y0,x1,y1))return 0; int Ans = 0; if(o->self(x0,y0,x1,y1))Ans ++; return Ans+Query(o->ls)+Query(o->rs); } void dfs(node *p){ if(!p)return; dfs(p->ls); pt[++len]=p->point; dfs(p->rs); delete p; } inline void rebuild(node *&o){ len = 0; register int split = o->split;dfs(o); build(o,1,len,split); } void insert(node *&o,Point po,int d=0){ if(!o){o=new node(po,d);return;} if(po[d]<o->point[d])insert(o->ls,po,d^1); else insert(o->rs,po,d^1); o->Maintain(); if(o->bad())need = o; } inline void ins(node *&o,Point po){ need = NULL; insert(o,po); if(need!=NULL)rebuild(need); } struct Seg_tree{ Seg_tree *ls,*rs; node *root; Seg_tree(){ ls=rs=NULL; root=NULL; } }*root; void Seg_insert(Seg_tree *&o,int l,int r,Point x,int val){ if(!o) o = new Seg_tree(); ins(o->root,x); if(l==r)return; int mid = l+r>>1; if(val<=mid)Seg_insert(o->ls,l,mid,x,val); else Seg_insert(o->rs,mid+1,r,x,val); } inline int Seg_Query(Seg_tree *o){ if(!o)return 0; return Query(o->root); } inline void Ask(){ x0=read<int>()^Ans,y0=read<int>()^Ans,x1=read<int>()^Ans,y1=read<int>()^Ans; register int k = read<int>()^Ans; if(Seg_Query(root)<k){ Ans = 0; printf("NAIVE!ORZzyz.\n"); return; } int l=1,r=inf; Seg_tree *rt=root; while(l<r){ int mid = l+r>>1,ans=Seg_Query(rt->rs); if(k>ans)k-=ans,rt=rt->ls,r=mid; else rt=rt->rs,l=mid+1; } printf("%d\n",Ans=l); } inline void change(){ Point cur; cur[0]=read<int>()^Ans;cur[1]=read<int>()^Ans; int val = read<int>()^Ans; Seg_insert(root,1,inf,cur,val); } int main(){ n=read<int>();Q=read<int>(); while(Q--){ register int tmp = read<int>(); if(tmp == 1)change(); else Ask(); } }