bzoj 2002 link cut tree(LCT)

61 篇文章 0 订阅
6 篇文章 0 订阅

题意:n个位置,第i个位置有一个弹力系数为ki的装置,编号从0~n-1,会被弹到i+ki的位置。如果i+ki处无装置,则弹飞否则继续。

两个操作:

1、1 x 输出从第x处开始弹几次被弹飞

2、2 x y x处装置的弹力系数改为y

LCT基础题

注意编号是0~n-1,这里我们都加1处理,使得范围为1~n

我们很容易发现一个性质:有无数个点可以到达同一个点,但一个点只能到达一个固定的点

所以令father[i]=i+ki

对于i>n所有已经弹飞的点,father[i]=0;

对于i+ki>n的点,干脆直接让father[i]=n+1

那么我们对于操作1,就是输出在x所对应的Auxiliary tree中,x到根节点的节点数

对于操作2,就是更改一下father[x]

因为我们连的是有向边,所以不需要翻转

所以,先access(x),再splay(x),把son[x,0]断掉独立出去,再更新father[x],更新方法见上

var
        n,m,p,x,y        :longint;
        father,size      :array[-1..200010] of longint;
        son              :array[-1..200010,0..1] of longint;
        root             :array[-1..200010] of boolean;
        i                :longint;
procedure update(x:longint);
begin
   size[x]:=size[son[x,0]]+size[son[x,1]]+1;
end;

procedure r_ro(f:longint);
var
        x:longint;
begin
   x:=son[f,0];
   son[f,0]:=son[x,1];
   father[son[x,1]]:=f;
   if f=son[father[f],0] then son[father[f],0]:=x
     else if f=son[father[f],1] then son[father[f],1]:=x;
   father[x]:=father[f];
   father[f]:=x;
   son[x,1]:=f;
   root[x]:=root[x] xor root[f];
   root[f]:=root[x] xor root[f];
   update(f); update(x);
end;

procedure l_ro(f:longint);
var
        x:longint;
begin
   x:=son[f,1];
   son[f,1]:=son[x,0];
   father[son[x,0]]:=f;
   if f=son[father[f],0] then son[father[f],0]:=x
     else if f=son[father[f],1] then son[father[f],1]:=x;
   father[x]:=father[f];
   father[f]:=x;
   son[x,0]:=f;
   root[x]:=root[f] xor root[x];
   root[f]:=root[f] xor root[x];
   update(f); update(x);
end;

procedure splay(x:longint);
begin
   while not root[x] do
     if x=son[father[x],0] then r_ro(father[x]) else l_ro(father[x]);
end;

procedure access(x:longint);
var
        y:longint;
begin
   splay(x);
   while father[x]<>0 do
   begin
      y:=father[x];
      splay(y);
      root[son[y,1]]:=true;
      root[x]:=false;
      son[y,1]:=x;
      update(y);
      splay(x);
   end;
end;

begin
   read(n);
   for i:=1 to n do
   begin
      read(x);
      if i+x>n then father[i]:=n+1 else father[i]:=i+x;
   end;
   fillchar(son,sizeof(son),255);
   fillchar(root,sizeof(root),true);
   for i:=1 to n+1 do size[i]:=1;
   read(m);
   for i:=1 to m do
   begin
      read(p,x);
      inc(x);
      if p=1 then
      begin
         access(x);
         splay(x);
         writeln(size[son[x,0]]);
      end else
      begin
         read(y);
         if x+y>n then y:=n+1 else y:=x+y;
         access(x);
         splay(x);
         father[son[x,0]]:=0;
         root[son[x,0]]:=true;
         son[x,0]:=-1;
         update(x);
         father[x]:=y;
      end;
   end;
end.
—— by Eirlys








  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值