树套树
名字看上去很高端很酷炫,其实不难,说白了就是树上建树。什么是树上建树?比如一个区间【1,5】,那么建成线段树就有【1,5】【1,3】【4,5】【1,2】【3】【4】【5】【1】【2】这么多个节点,现在我们把这个节点都变成一棵树(平衡树或者线段数),然后把区间内每个点都上入这个平衡树中,比如【1,3】,那么我们就把【1,3】里面三个数都加到一棵平衡树中,这样就可以直接得到【1,3】中每个树的排名(或者一些其他的工作)。
由于treap各种短各种方便,bit各种短各种方便,线段树各种快各种常数小(对于平衡树来说,而且此时线段树多是权值线段数)。so,蒟蒻至今只写过bit套treap,bit套线段树。
1、线段数套treap
建树过程
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
procedure maketree(x,l,r:longint); var i,mid:longint; begin with tree[x] do begin left:=l; right:=r; root:=0; for i:=l to r do insert(root,num[i]); end; if l=r then exit; mid:=(l+r)>>1; maketree(x<<1,l,mid); maketree(x<<1+1,mid+1,r); end;
用的时候
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
function query(x,l,r,y:longint):longint; var mid:longint; begin with tree[x] do begin if (l=left) and (r=right) then exit(rank(root,y)); mid:=(left+right)>>1; if r<=mid then exit(query(x<<1,l,r,y)) else if l>mid then exit(query(x<<1+1,l,r,y)) else exit(query(x<<1,l,mid,y)+query(x<<1+1,mid+1,r,y)); end; end;
然后treap该怎么用怎么用。
2、bit套treap
bit中i节点的区间为【i-lowbit(i)+1,i】;
建树过程:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
fillchar(root[0],sizeof(root[0]),0); for i:=1 to n do begin root[i]:=0; for j:=i-lowbit(i)+1 to i do insert(root[i],num[j]); end; end;
修改和查询
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
procedure del(x:longint); var old:longint; begin old:=x; x:=hash[x]; while x<=n do begin delete(root[x],old); inc(x,lowbit(x)); end; end; function askbig(x,y:longint):longint; var ans:longint; begin ans:=0; while x>0 do begin ans:=ans+getbig(root[x],y); dec(x,lowbit(x)); end; exit(ans); end;
不过就是bst在某些地方有点问题,比如询问【l,r】的区间,可能会出现每个点i加入后【i-lowbit(i)+1,i】不属于【l,r】,所以我们用bit时,除了i点对应的【i-lowbit(i)+1,i】区间外,还要在加一个只包含i这个点的bst。方便以后用吧。
取区间的方法,sroot保存的是区间的根,然后以后直接for一边就可以访问区间内所以的根了)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
procedure before(l,r:longint); var i,k:longint; begin sum:=0; i:=r; while i>=l do begin k:=i-lowbit(i)+1; if k>=l then begin inc(sum); sroot[sum]:=root[i]; i:=k-1; end else begin inc(sum); sroot[sum]:=root2[i]; dec(i); end; end; end;
3、bit套线段树
这个东西跑起来快,而且写起来比bst短,挺赞的。要注意的就是要见权值线段树。
建立过程:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
procedure build; var i,j,x,mid:longint; begin tot:=n; for i:=1 to n do begin root[i]:=i; tree[i].left:=0; tree[i].right:=mm; tree[i].lson:=0; tree[i].rson:=0; end; for i:=1 to n do for j:=i-lowbit(i)+1 to i do begin x:=root[i]; while true do begin inc(tree[x].sum); if tree[x].left=tree[x].right then break; mid:=(tree[x].left+tree[x].right)>>1; if num[j]<=mid then begin if tree[x].lson=0 then addson(tree[x].lson,tree[x].left,mid); x:=tree[x].lson; end else begin if tree[x].rson=0 then addson(tree[x].rson,mid+1,tree[x].right); x:=tree[x].rson; end; end; end; end;
修改过程:(addson,表示加点)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
procedure change(i,new:longint); var old,x,mid:longint; begin old:=num[i]; num[i]:=new; while i<=n do begin x:=root[i]; while true do begin inc(tree[x].sum); if tree[x].left=tree[x].right then break; mid:=(tree[x].left+tree[x].right)>>1; if new<=mid then begin if tree[x].lson=0 then addson(tree[x].lson,tree[x].left,mid); x:=tree[x].lson; end else begin if tree[x].rson=0 then addson(tree[x].rson,mid+1,tree[x].right); x:=tree[x].rson; end; end; x:=root[i]; while true do begin dec(tree[x].sum); if tree[x].left=tree[x].right then break; mid:=(tree[x].left+tree[x].right)>>1; if old<=mid then x:=tree[x].lson else x:=tree[x].rson; end; inc(i,lowbit(i)); end; end;
bz题目:
1901: Zju2112 Dynamic Rankings
2453: 维护队列
2141: 排队
3295: [Cqoi2011]动态逆序对