Treap:查找第k大元素
线段树、树状数组虽然查找第k大元素很方便,树状数组代码更是相当短。但是,两者必须要求数据为一定范围内的整数,否则就不能用区间和来查找第k大元素了。所以,学习用BST查找第k大元素是很有必要的。下面给出代码,Pascal版本的Treap查找第k大元素,写得很丑。
{ 小根堆实现,支持插入、删除、findkth等操作,其它的什么findmin什么的应该不难。 主要是要维护一个size和cnt域,另外每次旋转啊插入啊删除啊都要更新一下size域 以编程简单的treap也要写一百多行,当然可以精简一些代码,如果是C/C++应该更短 2011-08-12 22:45 } const INF=19930317; var t:array[0..1000000] of record x,aux,l,r,size,cnt:longint end; i,j,k,root,x,n,m,size:longint; procedure modify(i:longint); begin t[i].size:=t[t[i].l].size+t[t[i].r].size+t[i].cnt; end; procedure left(var i:longint); var j:longint; begin j:=t[i].r; t[i].r:=t[j].l; t[j].l:=i; modify(i); i:=j; modify(i); end; procedure right(var i:longint); var j:longint; begin j:=t[i].l; t[i].l:=t[j].r; t[j].r:=i; modify(i); i:=j; modify(i); end; procedure insert(var i:longint; x:longint); begin if i=0 then begin inc(size); i:=size; t[size].size:=1; t[size].cnt:=1; t[size].l:=0; t[size].r:=0; t[size].aux:=random(INF); t[size].x:=x; end else begin if t[i].x=x then begin inc(t[i].cnt); end else if x<t[i].x then begin insert(t[i].l,x); if t[t[i].l].aux<t[i].aux then right(i); end else if x>t[i].x then begin insert(t[i].r,x); if t[t[i].r].aux<t[i].aux then left(i); end; modify(i); end; end; procedure delete(var i:longint; x:longint); begin if i=0 then exit; if x<t[i].x then delete(t[i].l,x) else if x>t[i].x then delete(t[i].r,x) else begin if t[i].cnt>1 then dec(t[i].cnt) else if t[i].l=0 then i:=t[i].r else if t[i].r=0 then i:=t[i].l else if t[t[i].l].aux < t[t[i].r].aux then begin right(i); delete(t[i].r,x); end else begin left(i); delete(t[i].l,x); end end; if i<>0 then modify(i); end; function findkth(i,k:longint):longint; begin if k<=t[t[i].l].size then exit(findkth(t[i].l,k)); if k<=t[t[i].l].size+t[i].cnt then exit(t[i].x); exit(findkth(t[i].r,k-t[t[i].l].size-t[i].cnt)); end; begin randomize; t[0].aux:=INF; readln(n); for i:=1 to n do begin read(x); insert(root,x); end; readln(m); for i:=1 to m do begin read(x); writeln(findkth(root,x)); end; readln(m); for i:=1 to m do begin read(x); delete(root,x); end; readln(m); for i:=1 to m do begin read(x); writeln(findkth(root,x)); end; end.