POJ2104 K-th Number——划分树——pku2104

按照铎铎大牛的AC Record做的第一题,就被虐得很惨。

这是划分树的模板题。划分树,主要是求无更改的情况下区间第k小值。建树和线段树有些类似,但是划分树是在排序的基础上,左子树记录比中间值小的值,右子树记录比中间值大的数,在每棵子树中不改变原数列中的顺序。

查找也类似线段树,规定查找区间,定义函数Find(code,l,r,kth,dep),code为当前查找到的节点值,l,r是区间左右界,为闭区间,dep代表当前查找的深度。如果l,r与code的管辖区间相同就返回b[l+kth-1](b为排好序的数列),否则令t1、t2为[tree[code].left,l-1]进入左子树的数的个数和[tree[code].left,r]进入左子树的个数。

如果t1-t2>=kth,就查找左子树,边界为[tree[code].left+tree[code].left+t2,tree[code].left+tree[code].left+t1-1]

(也就是[tree[code].left+[tree[code].left,l-1]区间进入左子树的数的个数,tree[code].left+[tree[code].left,r]进入左子树的数的个数]),

否则查找右子树,边界为[tree[code].mid+1+l-tree[code].left-t2,tree[code].mid+1+r-tree[code].left-t1]

(也就是[tree[code].mid+[tree[code].left,l-1]区间进入右子树的数的个数,tree[code].mid+[tree[code].left,r]进入右子树的数的个数])

 

有点繁琐,自己推导一下就行了。

 

代码:

Program poj2104;//By_Thispoet

Const 

	maxn=100005;

Var

	i,j,k,m,n,p,q,x,y,z				:Longint;

	g,rel							:Array[0..20,0..maxn]of Longint;

	b								:Array[1..maxn]of Longint;

	tree							:ARray[1..maxn*10]of record left,right,mid:Longint; end;

	

Procedure Qsort(l,r:Longint);

var i,j,k,temp:Longint;

begin

	i:=l;j:=r;k:=b[i+random(j-i+1)];

	repeat

		while b[i]<k do inc(i);

		while b[j]>k do dec(j);

		if i<=j then 

			begin

				temp:=b[i];b[i]:=b[j];b[j]:=temp;

				inc(i);dec(j);

			end;

	until i>j;

	if l<j then Qsort(l,j);

	if i<r then Qsort(i,r);

end;

	

	

Procedure Build_Tree(code,l,r,dep:Longint);

var i,j,k,ll,rr:Longint;

begin

	with tree[code] do 

		begin

			left:=l;right:=r;mid:=(l+r)>>1;

			if l=r then exit;

			ll:=l-1;rr:=mid;

			for i:=l to r do 

				begin

					if (g[dep-1,i]<=b[mid])and(ll<mid)then 

						begin

							inc(ll);

							g[dep,ll]:=g[dep-1,i];

							if l>i-1 then rel[dep,i]:=1 else rel[dep,i]:=rel[dep,i-1]+1;

						end else

							begin

								inc(rr);

								g[dep,rr]:=g[dep-1,i];

								if l>i-1 then rel[dep,i]:=0 else rel[dep,i]:=rel[dep,i-1];

							end;

				end;

			Build_Tree(code*2,l,mid,dep+1);

			Build_Tree(code*2+1,mid+1,r,dep+1);

		end;

end;

	

	

Function Find(code,l,r,k,dep:Longint):Longint;

var t1,t2,tnum,ll,rr:Longint;

begin

	if (tree[code].left=l)and(tree[code].right=r)then exit(b[l+k-1]);

	t1:=rel[dep,r];

	if tree[code].left>l-1 then t2:=0 else t2:=rel[dep,l-1];

	tnum:=t1-t2;

	if tnum>=k then 

		begin

			ll:=tree[code].left+t2;

			rr:=tree[code].left+t1-1;

			find:=Find(code*2,ll,rr,k,dep+1);

		end else 

			begin

				ll:=tree[code].mid+1+l-tree[code].left-t2;

				rr:=ll-l+r-tnum;

				find:=Find(code*2+1,ll,rr,k-tnum,dep+1);

			end;

end;

	

	

BEGIN



	readln(n,m);

	randomize;

	for i:=1 to n do

		begin

			read(g[0,i]);

			b[i]:=g[0,i];

		end;

	Qsort(1,n);

	Build_Tree(1,1,n,1);

	while m>0 do 

		begin

			readln(x,y,z);

			writeln(Find(1,x,y,z,1));

			dec(m);

		end;



END.

你可能感兴趣的:(number)