简单易学的平衡树,虽然随机值要靠rp,但一般来说还是不会被卡的。
treap=tree+heap,treap有两个关键值,id和权值。
一般的二叉排序树难以维持自身平衡,容易退化成链,所以就有了id值。
id靠随机,对我们来说无实际意义,由堆序维护,听起来有点搞笑,但确实在大多数情况下能维护平衡。
w是节点自身属性,对我们来说有实际意义,遵循二叉排序树的规则,即根节点左子树均小于根,右子树均大于根,递归定义。
由于treap兼有二者特点,所以维护的时候,不能单一的按tree或heap来,于是诞生了旋转的操作,既能维护堆序,又能维护树序。
在treap中分为左旋和右旋两种:
右旋
1 1
\ \
2 3
/ \ ——————> / \
3 4 5 2
/ \
5 4
左旋
1 1
\ \
2 4
/ \ ——————> / \
3 4 2 5
\ /
5 3
插入,先按二叉排序树插入,再维护id堆序(左旋,右旋实现,同时维护信息)
删除,找到指定节点,不断通过左旋右旋下沉,下沉至链节点(至少有一个子树为空)用其不为空子节点代替
基本操作就这些,还附带找k大,k小值等等操作
推荐模板http://blog.youkuaiyun.com/cjoilmd/article/details/6629062
lmd同学借助splay模板,写的非递归版treap,同时还有易错点。
总的来说,调试起来不是一般的麻烦,还是左偏树好调试。
const maxr=100000;
var n,m,ss,ll,rr:longint;
size,l,r,w,id,rt,a:array[0..200000]of longint;
x,y,q,z,ans:array[0..500000]of longint;
check:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y)
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y)
end;
procedure right(x:longint);
var y,z:longint;
begin
y:=rt[x];z:=rt[y];
if l[z]=y then l[z]:=x else r[z]:=x;rt[x]:=z;
l[y]:=r[x];rt[r[x]]:=y;
r[x]:=y;rt[y]:=x;
size[x]:=size[y];
size[y]:=size[l[y]]+size[r[y]]+1
end;
procedure left(x:longint);
var y,z:longint;
begin
y:=rt[x];z:=rt[y];
if l[z]=y then l[z]:=x else r[z]:=x;rt[x]:=z;
r[y]:=l[x];rt[l[x]]:=y;
l[x]:=y;rt[y]:=x;
size[x]:=size[y];
size[y]:=size[l[y]]+size[r[y]]+1
end;
function ori(x,y:longint):longint;
begin
inc(ss);id[ss]:=random(maxr);
w[ss]:=x;size[ss]:=1;
l[ss]:=0;r[ss]:=0;rt[ss]:=y;
ori:=ss
end;
procedure ins(p:longint);
var x:longint;
begin
x:=1;
while true do begin
inc(size[x]);
if p>w[x] then begin
if r[x]=0 then begin r[x]:=ori(p,x);x:=r[x];break end
else x:=r[x]
end
else begin
if l[x]=0 then begin l[x]:=ori(p,x);x:=l[x];break end
else x:=l[x]
end
end;
while id[x]<id[rt[x]] do
if l[rt[x]]=x then right(x) else left(x)
end;
procedure low(x:longint);
var ll,rr:longint;
begin
ll:=l[x];rr:=r[x];
if id[ll]<id[rr] then right(ll) else left(rr)
end;
procedure del(p:longint);
var x,y,z:longint;
begin
x:=1;
while w[x]<>p do if w[x]<p then x:=r[x] else x:=l[x];
id[x]:=maxlongint;
while (l[x]<>0)and(r[x]<>0) do low(x);
y:=rt[x];
if l[x]=0 then z:=r[x] else z:=l[x];
if l[y]=x then l[y]:=z else r[y]:=z;
if z<>0 then rt[z]:=y;
while id[y]<>-maxlongint do begin
dec(size[y]);
y:=rt[y]
end;
dec(size[y])
end;
function findmin(q:longint):longint;
var x:longint;
begin
x:=1;inc(q);
while true do begin
if q=size[l[x]]+1 then exit(w[x])
else if q<=size[l[x]] then x:=l[x]
else begin
q:=q-size[l[x]]-1;
x:=r[x]
end
end
end;
procedure work;
var i,j:longint;
begin
rr:=0;x[0]:=x[1];
for i:=1 to m do begin
for j:=x[i-1] to min(x[i]-1,y[i-1]) do del(a[j]);
for j:=max(rr+1,x[i]) to y[i] do ins(a[j]);
ans[z[i]]:=findmin(q[i]);rr:=y[i]
end
end;
procedure qsort(l,r:longint);
var i,j,xx,yy,c:longint;
begin
i:=l;j:=r;xx:=x[(l+r)>>1];yy:=y[(l+r)>>1];
repeat
while (x[i]<xx)or((x[i]=xx)and(y[i]<yy)) do inc(i);
while (xx<x[j])or((xx=x[j])and(yy<y[j])) do dec(j);
if not(i>j) then begin
c:=x[i];x[i]:=x[j];x[j]:=c;
c:=y[i];y[i]:=y[j];y[j]:=c;
c:=q[i];q[i]:=q[j];q[j]:=c;
c:=z[i];z[i]:=z[j];z[j]:=c;
inc(i);dec(j)
end
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j)
end;
procedure init;
var i:longint;
begin
readln(n,m);
for i:=1 to n do read(a[i]);readln;
for i:=1 to m do begin
readln(x[i],y[i],q[i]);
z[i]:=i
end;
qsort(1,m);
id[1]:=-maxlongint;w[1]:=-maxlongint;ss:=1;
size[0]:=0;
work;
for i:=1 to m do writeln(ans[i])
end;
begin
randomize;
init
end.