以前的空间几道平衡树

Posted Macaulish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以前的空间几道平衡树相关的知识,希望对你有一定的参考价值。

vijos 1459 车展

一个空的树.. 依次添加1到n。就能解决左端点为1的所有询问了吧。然后从2开始做一遍啊...n方logn得到全部答案。”神牛的话就是这么吊……看上去没什么信息量但还是水很深……实际上要维护子树内元素和。也就是我程序里面写的change,lsum指左子树中所有点的值得和,rsum指右子树中所有点的值得和,zsum指整个子树中节点的和,也就是lsum+rsum+本节点的值。在计算代价的时候是这样的……假设从i加到j需到的代价为sum,首先找到中间值,就是排名为(j-i)div2+1的点l,然后在sum上加上“这个节点左子树上的点的总和与这个节点的值*左子树节点个数的绝对值”,由于后者要比前者大……所以就是key[l]*s[left[l]]。右子树就是反过来。但是sum的值还不止这些,还需要在递归的时候加上一些值,即如果这个点是左儿子,那sum就要加上他爹和他右兄弟上所有点的值与他爹和他右兄弟上所有点数*这个key[l]的值,就是rsum[t]+key[t]-(s[right[t]]+1)*l,如果是右子树也是一样……这样就没了。最后注意,一定要开int64,因为这个错误,wa了3次……     

const maxn=4000;

var key,s,left,right,a:array[0..maxn] of longint;

    lsum,rsum,zsum:array[0..maxn]of int64;
    tt,i,j,k,l,n,m,t:longint;
    f:array[0..2000,0..2000]of int64;
    sum:int64;

procedure change(t:longint);

begin

  lsum[t]:=zsum[left[t]];
  rsum[t]:=zsum[right[t]];
  zsum[t]:=lsum[t]+rsum[t]+key[t];

end;

procedure right_rotate(var t:longint);

var

  k:longint;

begin

   k:=left[t];
   left[t]:=right[k];
   right[k]:=t;
   s[k]:=s[t];
   s[t]:=s[left[t]]+s[right[t]]+1;
   change(t);
   change(k);
   t:=k;

end;

procedure left_rotate(var t:longint);

var

  k:longint;

begin

   k:=right[t];
   right[t]:=left[k];
   left[k]:=t;
   s[k]:=s[t];
   s[t]:=s[left[t]]+s[right[t]]+1;
   change(t);
   change(k);
   t:=k;

end;

procedure maintain(var t:longint;flag:boolean);

begin

if flag=false then
      if s[left[left[t]]]>s[right[t]] then
         right_rotate(t)
      else
         if s[right[left[t]]]>s[right[t]] then begin
            left_rotate(left[t]);
            right_rotate(t);
         end
         else
            exit   else
      if s[right[right[t]]]>s[left[t]] then
         left_rotate(t)
      else
         if s[left[right[t]]]>s[left[t]] then begin
            right_rotate(right[t]);
            left_rotate(t);
         end
         else
            exit;
   maintain(left[t],false);
   maintain(right[t],true);
   maintain(t,true);
maintain(t,false);

end;

procedure insert(var t,v:longint);

begin

if t=0 then begin
      inc(tt);
      t:=tt;
      key[t]:=v;
      s[t]:=1;
      left[t]:=0;
      right[t]:=0;
      lsum[t]:=0;
      rsum[t]:=0;
      zsum[t]:=key[t];
   end
   else begin
      inc(s[t]);
      if v<key[t] then begin
         insert(left[t],v);
         inc(lsum[t],v);
         inc(zsum[t],v);
      end
      else begin
         insert(right[t],v);
         inc(rsum[t],v);
         inc(zsum[t],v);
      end;
      maintain(t,v>=key[t]);
end;

end;

function select(var t:longint;k:longint):longint;

var

  l:longint;

begin

if k=s[left[t]]+1 then begin
      l:=key[t];
      sum:=s[left[t]]*l-lsum[t]+rsum[t]-s[right[t]]*l;
      exit(key[t]);
   end else
   if k<=s[left[t]] then begin
      l:=select(left[t],k);
      sum:=sum+rsum[t]+key[t]-(s[right[t]]+1)*l;
      exit(l)
   end
   else begin
      l:=select(right[t],k-1-s[left[t]]);
     sum:=sum+(s[left[t]]+1)*l-key[t]-lsum[t];
     exit(l);
end;

end;



begin

readln(n,m);

for i:=1 to n do
    read(a[i]);
  for i:=1 to n do
    f[i,i]:=0;
  for i:=1 to n-1 do begin
    fillchar(left,sizeof(left),0);
    fillchar(s,sizeof(s),0);
    fillchar(right,sizeof(right),0);
    fillchar(lsum,sizeof(lsum),0);
    fillchar(rsum,sizeof(rsum),0);
    fillchar(zsum,sizeof(zsum),0);
    fillchar(key,sizeof(key),0);   //傻逼又没有必要的初始化,去掉也行啦……
    tt:=0;
    t:=0;
    insert(t,a[i]);
    for j:=i+1 to n do begin
      insert(t,a[j]);
      sum:=0;
      k:=select(t,(j-i)div 2+1);
      f[i,j]:=sum;
    end;
  end;
  sum:=0;
  for i:=1 to m do
    begin
      readln(j,k);
      sum:=sum+f[j,k];
    end;
writeln(sum);

end.
View Code

vijos 1647 不差钱

var
  ans,tot,i,n,p,t:longint;
  s,left,right,key,value:array[0..101000]of longint;
  a:array[0..1000010]of longint;
  m:int64;
 
procedureleftrotate(var t:longint);
var
  k:longint;
begin
  k:=right[t];
  right[t]:=left[k];
  left[k]:=t;
  s[k]:=s[t];
  s[t]:=s[left[t]]+s[right[t]]+1;
  t:=k;
end;
 
procedurerightrotate(var t:longint);
var
  k:longint;
begin
  k:=left[t];
  left[t]:=right[k];
  right[k]:=t;
  s[k]:=s[t];
  s[t]:=s[left[t]]+s[right[t]]+1;
  t:=k;
end;
 
proceduremaintain(var t:longint);
begin
  if s[left[left[t]]]>s[right[t]] then begin
    rightrotate(t);
    maintain(right[t]);
    maintain(t);
    exit;
  end;
  if s[right[left[t]]]>s[right[t]] then begin
    leftrotate(left[t]);
    rightrotate(t);
    maintain(left[t]);
    maintain(right[t]);
    maintain(t);
    exit;
  end;
  if s[right[right[t]]]>s[left[t]] then begin
    leftrotate(t);
    maintain(left[t]);
    maintain(t);
    exit;
  end;
  if s[left[right[t]]]>s[left[t]] then begin
    rightrotate(right[t]);
    leftrotate(t);
    maintain(left[t]);
    maintain(right[t]);
    maintain(t);
  end;
end;
 
procedureinsert(var t:longint;v:longint);
begin
  if t=0 then begin
    inc(tot);
    t:=tot;
    s[tot]:=1;
    left[tot]:=0;
    right[tot]:=0;
    key[tot]:=v;
    value[ans]:=v;
  end
  else begin
    s[t]:=s[t]+1;
    if v<=key[t] then
      insert(left[t],v)
    elseinsert(right[t],v);
    maintain(t);
  end;
end;
 
functionselect(var t:longint;k:longint):longint;
var
  l:longint;
begin
  if k=s[left[t]]+1 then
    select:=key[t]
  else begin
    if k<=s[left[t]] then
      select:=select(left[t],k)
    else select:=select(right[t],k-1-s[left[t]]);
  end;
end;
 
begin
  readln(m);
  t:=0;
  tot:=0;
  ans:=0;
  fillchar(a,sizeof(a),0);
  read(p);
  while p<>0 do begin
    read(n);
    case p of
      1:begin
        inc(ans);
        insert(t,n);
        inc(a[n]);
        end;
      2:dec(a[value[n]]);
      3:begin
        i:=select(t,ans-n+1);
        if i>m then writeln(\'Dui bu qi,Mei you.\')
        else
          if a[i]>0 then writeln(\'You. \',i,\' Yuan.\')
          else writeln(\'Mei you. Zhe ge ke yi you. Zhe ge zhen mei you!\')
      end;
    end;
    read(p);
  end;
end.
View Code

 

以上是关于以前的空间几道平衡树的主要内容,如果未能解决你的问题,请参考以下文章

平衡二叉树专题

树套树初探

2019.3.16 最小生成树之最平衡生成树

范浩强treap——可持久化

P3380 线段树套平衡树

以前的空间Poj 3071 Cut the Sequence