【以前的空间】树套树入门总结

树套树

名字看上去很高端很酷炫,其实不难,说白了就是树上建树。什么是树上建树?比如一个区间【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

建树过程

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;
View Code

用的时候

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;
View Code

然后treap该怎么用怎么用。

 

2、bit套treap

 bit中i节点的区间为【i-lowbit(i)+1,i】;

 建树过程:

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;
View Code

修改和查询

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;
View Code

不过就是bst在某些地方有点问题,比如询问【l,r】的区间,可能会出现每个点i加入后【i-lowbit(i)+1,i】不属于【l,r】,所以我们用bit时,除了i点对应的【i-lowbit(i)+1,i】区间外,还要在加一个只包含i这个点的bst。方便以后用吧。

取区间的方法,sroot保存的是区间的根,然后以后直接for一边就可以访问区间内所以的根了)

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;
View Code

 

3、bit套线段树

这个东西跑起来快,而且写起来比bst短,挺赞的。要注意的就是要见权值线段树。

建立过程:

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;
View Code

修改过程:(addson,表示加点)

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;
View Code

bz题目:

1901: Zju2112 Dynamic Rankings

2453: 维护队列

2141: 排队

3295: [Cqoi2011]动态逆序对

 

posted @ 2017-03-02 19:17  Macaulish  阅读(306)  评论(0编辑  收藏  举报