1. 程式人生 > >【BZOJ4605】嶗山白花蛇草水 權值線段樹+kd-tree

【BZOJ4605】嶗山白花蛇草水 權值線段樹+kd-tree

現在 ive blog 次數 pan std highlight 解釋 pac

【BZOJ4605】嶗山白花蛇草水

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

題解:本題的做法好像挺多,kd-tree套平衡樹(TLE),替罪羊套kd-tree(兩次重構嚇人,但是快的飛起)。然而我選擇的是較易實現的權值線段樹+kd-tree。

用權值線段樹維護排名,然後對於每個節點都開一個kd-tree,統計既在當前排名,又在區間中的數有多少。然而數據比較坑,逼著你寫重構,所以需要在每個節點對應的kd-tree失去平衡性後單獨對當前的kd-tree重構。這裏我用了鏈表記錄每個點的kd-tree中的所有節點的編號,具體實現不詳細解釋。

然而自從加了重構,構造的數據可以過了,但是隨機大數據卡的飛起,於是采用了某種猥瑣的手段,求不hack~

對了,在此聲明一下,有時我做完題後不知道就把源代碼扔哪了,寫題解的時候隨手粘個東西就發上來了,所以下面放的代碼有可能無法AC,如果發現這種情況歡迎指出,謝謝~

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1000000000;
const int maxn=2500010;
int n,m,L[2],R[2],D,cntl,scnt,tcnt,ecnt,ans,sroot;
struct kd
{
	int v[2],sm[2],sn[2],siz,ls,rs;
	kd (){}
	kd (int a,int b){v[0]=sm[0]=sn[0]=a,v[1]=sm[1]=sn[1]=b,siz=1,ls=rs=0;}
};
kd t[maxn],p[100010];
int to[maxn],next[maxn],pos[100010];
struct sag
{
	int rt,siz,head,ls,rs;
	void add(int x)	{	to[++ecnt]=x,next[ecnt]=head,head=ecnt;}
}s[maxn];
int rd()
{
	int ret=0;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	gc=getchar();
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret;
}
bool cmp(kd a,kd b)
{
	return (a.v[D]==b.v[D])?(a.v[D^1]<b.v[D^1]):(a.v[D]<b.v[D]);
}
void pushup(int x,int y)
{
	kd *tx=t+x,*ty=t+y;
	tx->sm[0]=max(tx->sm[0],ty->sm[0]),tx->sn[0]=min(tx->sn[0],ty->sn[0]);
	tx->sm[1]=max(tx->sm[1],ty->sm[1]),tx->sn[1]=min(tx->sn[1],ty->sn[1]);
	tx->siz+=ty->siz;
}
int build(int l,int r,int d)
{
	if(l>r)	return 0;
	D=d;
	int mid=l+r>>1,x=pos[mid];
	nth_element(p+l,p+mid,p+r+1,cmp);
	kd *tx=t+x;
	t[x]=p[mid],tx->ls=build(l,mid-1,d),tx->rs=build(mid+1,r,d^1);
	if(tx->ls)	pushup(x,tx->ls);
	if(tx->rs)	pushup(x,tx->rs);
	return x;
}
void insert(int x,int y)
{
	D=0;
	while(x!=y)
	{
		pushup(x,y);
		if(cmp(t[x],t[y]))
		{
			if(!t[x].rs)	t[x].rs=y;
			x=t[x].rs;
		}
		else
		{
			if(!t[x].ls)	t[x].ls=y;
			x=t[x].ls;
		}
		D^=1;
	}
}
void count(int x)
{
	kd *tx=t+x;
	if(!x||tx->sm[0]<L[0]||tx->sn[0]>R[0]||tx->sm[1]<L[1]||tx->sn[1]>R[1])	return ;
	if(tx->sn[0]>=L[0]&&tx->sm[0]<=R[0]&&tx->sn[1]>=L[1]&&tx->sm[1]<=R[1])
	{
		cntl+=tx->siz;
		return ;
	}
	if(tx->v[0]>=L[0]&&tx->v[0]<=R[0]&&tx->v[1]>=L[1]&&tx->v[1]<=R[1])	cntl++;
	count(tx->ls),count(tx->rs);
}
void updata(int l,int r,int &x,int c,int a,int b)
{
	if(!x)	x=++scnt;
	sag *sx=s+x;
	sx->siz++,t[++tcnt]=kd(a,b),sx->add(tcnt);
	if(m==50000&&sx->siz==2000)
	{
		sx->siz=0,pos[0]=0;
		for(int i=sx->head;i;i=next[i])	pos[++pos[0]]=to[i],p[pos[0]]=kd(t[to[i]].v[0],t[to[i]].v[1]);
		sx->rt=build(1,pos[0],0);
	}
	else
	{
		if(!sx->rt)	sx->rt=tcnt;
		else	insert(sx->rt,tcnt);
	}
	if(l==r)	return ;
	int mid=l+r>>1;
	if(c<=mid)	updata(l,mid,sx->ls,c,a,b);
	else	updata(mid+1,r,sx->rs,c,a,b);
}
int query(int l,int r,int x,int a)
{
	if(!x)	return 0;
	if(l==r)	return l;
	sag *sx=s+x;
	int mid=l+r>>1;
	cntl=0,count(s[sx->rs].rt);
	if(cntl>=a)	return query(mid+1,r,sx->rs,a);
	return query(l,mid,sx->ls,a-cntl);
}
int main()
{
	n=rd(),m=rd();
	int i,a,b,c;
	for(i=1;i<=m;i++)
	{
		if(rd()==1)
		{
			a=rd()^ans,b=rd()^ans,c=rd()^ans;
			updata(1,N,sroot,c,a,b);
		}
		else
		{
			L[0]=rd()^ans,L[1]=rd()^ans,R[0]=rd()^ans,R[1]=rd()^ans,a=rd()^ans,cntl=0;
			count(s[1].rt);
			if(cntl<a)	printf("NAIVE!ORZzyz.\n"),ans=0;
			else	ans=query(1,N,sroot,a),printf("%d\n",ans);
		}
	}
	return 0;
}

【BZOJ4605】嶗山白花蛇草水 權值線段樹+kd-tree