按照铎铎大牛的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.