BZOJ 4605: 崂山白花蛇草水 树套树 权值线段树套kdtree

4605: 崂山白花蛇草水

Time Limit: 80 Sec  Memory Limit: 512 MB
Submit: 527  Solved: 153
[Submit][Status][Discuss]

Description

神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水。凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了。蒟蒻Bob特地为他准备了999,999,999,999,999,999瓶崂山白花蛇草水,想要灌神犇Aleph。神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bob最终答应了他的请求,但蒟蒻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

外层权值线段树

内层kdtree

//做完之后 我觉得内层写二维线段树才是明智的选择


调试要注意的

替罪羊树重构

不要puhup当前根节点的fa

//万一是0就GG 但可以特判就是常数打 因为根本不会改变fa维护的信息

更可怕的就是把一个anc写成了ans...

//以后这俩再也不一起用了555

最可怕的就是

一会想在kdtree的模板套替罪羊

一会想在替罪羊的模板里套kdtree

最后发现在kdtree里写了个替罪羊 替罪羊里不知道哪里又换成了kdtree

调哭我


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef double db;
typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=500100,M=int(1e9),MN=4000100;
const db alpha=0.75;

int ans;

int cur;
struct node
{
	int d[2],mn[2],mx[2],s[2],pos;
	inline int& operator [](int x){return d[x];}
	friend bool operator <(const node &x,const node &y){return x.d[cur]<y.d[cur];}
}st[N>>2],tr[MN];

int tot;
int fa[MN],size[MN];int num[2];

struct kdtree
{
	node T;
	int root,top,res;
	kdtree(){top=root=0;}
	
	inline void pushup(int k)
	{
		for(int i=0;i<2;++i)
		{
			tr[k].mn[i]=tr[k].mx[i]=tr[k][i];
			if(tr[k].s[0])
				tr[k].mn[i]=min(tr[k].mn[i],tr[tr[k].s[0]].mn[i]),
				tr[k].mx[i]=max(tr[k].mx[i],tr[tr[k].s[0]].mx[i]);
			if(tr[k].s[1])
				tr[k].mn[i]=min(tr[k].mn[i],tr[tr[k].s[1]].mn[i]),
				tr[k].mx[i]=max(tr[k].mx[i],tr[tr[k].s[1]].mx[i]);
		}
		size[k]=size[tr[k].s[0]]+size[tr[k].s[1]]+1;
	}
	
	inline bool balance(int k)
	{return alpha*size[k]>=db(max(size[tr[k].s[0]],size[tr[k].s[1]]));}
	
	void dfs(int k)
	{
		if(!k)return ;
		st[++top]=tr[k];
		dfs(tr[k].s[0]);dfs(tr[k].s[1]);
	}
	
	int build(int l,int r,int now)
	{
		if(l>r)return 0;
		cur=now;
		int mid=(l+r)>>1,k;
		nth_element(st+l,st+mid,st+r+1);
		k=st[mid].pos;
		tr[k].s[0]=build(l,mid-1,now^1);
		tr[k].s[1]=build(mid+1,r,now^1);
		if(tr[k].s[0])fa[tr[k].s[0]]=k;
		if(tr[k].s[1])fa[tr[k].s[1]]=k;
		pushup(k);
		return k;
	}
	
	void rebuild(int k,int d)
	{
		top=0;dfs(k);
		int anc=fa[k],son=(tr[anc].s[1]==k),now=build(1,top,d);
		fa[now]=anc;
		if(anc)tr[anc].s[son]=now;
		if(k==root)root=now;
	}
	
	void insert(int x,int y)
	{
		tr[++tot][0]=x;tr[tot][1]=y;
		tr[tot].pos=tot;
		pushup(tot);
		if(!root) {root=tot;return ;}
		int k=root,now(0),son,inv(0);
		while(1)
		{
			son=(tr[tot][now]>=tr[k][now]);
			if(!tr[k].s[son])
				{tr[k].s[son]=tot;fa[tot]=k;break;}
			else k=tr[k].s[son];
			now^=1; 
		}
		while(k)
		{
			pushup(k);
			if(!balance(k)) inv=k,son=now;
			k=fa[k];now^=1;
		}
		if(inv)rebuild(inv,son);
	}
	
	inline bool in(int a,int b,int c,int d)
	{return a<=T.mn[0] && c>=T.mx[0] && b<=T.mn[1] && d>=T.mx[1];}
	
	inline bool out(int a,int b,int c,int d)
	{return a>T.mx[0] || c<T.mn[0] || b>T.mx[1] || d<T.mn[1];}
	
	inline bool node_in(int a,int b,int c,int d)
	{return a<=T[0] && c>=T[0] && b<=T[1] && d>=T[1];}
	
	void query(int k,int a,int b,int c,int d)
	{
		if(!k)return ;
		T=tr[k];
		if(in(a,b,c,d)){res+=size[k];return ;}
		if(out(a,b,c,d))return ;
		if(node_in(a,b,c,d))res++;
		query(tr[k].s[0],a,b,c,d);
		query(tr[k].s[1],a,b,c,d);
		return ;
	}
	
	int kdquery(int a,int b,int c,int d)
	{
		res=0;query(root,a,b,c,d);
		return res;
	}	
}kd[MN];

struct seg_tree{int ls,rs;}str[MN];
int root,sz;

void insert(int &k,int l,int r,int val,int x,int y)
{
	if(!k)k=++sz;
	kd[k].insert(x,y);
	if(l==r)return ;
	int mid((l+r)>>1);
	val<=mid ? insert(str[k].ls,l,mid,val,x,y) : insert(str[k].rs,mid+1,r,val,x,y);
}

void query(int k,int l,int r,int a,int b,int c,int d,int rk)
{
	if(l==r){ans=l;return ;}
	int mid((l+r)>>1);
	int tmp=kd[str[k].rs].kdquery(a,b,c,d);
	tmp>=rk ? query(str[k].rs,mid+1,r,a,b,c,d,rk) : query(str[k].ls,l,mid,a,b,c,d,rk-tmp);
}

int main()
{
	int n=read(),Q=read();
	register int opt,a,b,c,d,val;
	while(Q--)
	{
		opt=read();
		a=read()^ans;b=read()^ans;
		switch(opt)
		{
			case 1:
				val=read()^ans;
				insert(root,1,M,val,a,b);
				break;
			case 2:
				c=read()^ans;d=read()^ans;
				val=read()^ans;
				if(a>c)swap(a,c);
				if(b>d)swap(b,d);
				if(kd[1].kdquery(a,b,c,d)<val)
					ans=0,puts("NAIVE!ORZzyz.");
				else 
					query(root,1,M,a,b,c,d,val),
					print(ans),puts("");
				break;
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值