现在的位置: 首页 > 综合 > 正文

bzoj2002

2018年01月15日 ⁄ 综合 ⁄ 共 2149字 ⁄ 字号 评论关闭

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3

动态树模板问题

link/cut tree来解决

其实也可以分块来搞……跟ioi的大象很像

每个点向他弹射到的点连边,弹飞的连向0,这样全图就形成了一棵树

询问的话,就是查询改点到根节点上有多少个节点

修改的话,就是更改一个点的祖先

{$inline on}
program bzoj2002;
var
  n,m,i,j,k,o:longint;
  fa,father,left,right,total:array [0..200001] of longint;


function sum (now:longint):longint;inline;
var
  ans:longint;
begin
  if now=0 then exit(0);
  ans:=0;
  repeat
    ans:=ans+total[now]+1;
    now:=right[now];
  until now=0;
  exit(ans);
end;

procedure rotate (son,fat:longint);
begin
  if father[fat]<>0 then
    begin
      if left[father[fat]]=fat then
        left[father[fat]]:=son
                               else
        right[father[fat]]:=son;
    end;
  father[son]:=father[fat];
  father[fat]:=son;
  if left[fat]=son then
    begin
      if right[son]<>0 then father[right[son]]:=fat;
      left[fat]:=right[son];
      right[son]:=fat;
      total[fat]:=total[fat]-total[son]-1;
    end
                   else
    begin
      if left[son]<>0 then father[left[son]]:=fat;
      right[fat]:=left[son];
      left[son]:=fat;
      total[son]:=total[son]+total[fat]+1;
    end;
end;

procedure access (now:longint);
var
  i,k,o:longint;
begin
  while fa[now]<>0 do
    begin
      while father[now]<>0 do rotate(now,father[now]);
      i:=now;
      while right[i]<>0 do i:=right[i];
      k:=fa[i];
      if k=0 then break;
      while father[i]<>0 do rotate(i,father[i]);
      while father[k]<>0 do rotate(k,father[k]);
      o:=0;
      if left[k]<>0 then
        begin
          o:=o-sum(left[k]);
          father[left[k]]:=0;
        end;
      o:=o+sum(i);
      left[k]:=i;
      father[i]:=k;
      total[k]:=total[k]+o;
      now:=k;
    end;
end;

begin
  read(n);
  for i:=1 to n do
    begin
      read(fa[i]);
      fa[i]:=fa[i]+i;
      if fa[i]>n then fa[i]:=0;
    end;
  read(m);
  for j:=1 to m do
    begin
      read(o);
      if o=1 then
        begin
          read(i);
          inc(i);
          access(i);
          while father[i]<>0 do rotate(i,father[i]);
          i:=right[i];
          writeln(sum(i)+1);
        end
             else
        begin
          read(i,k);
          inc(i);
          o:=i+k;
          if o>n then o:=0;
          if fa[i]=o then continue;
          while father[i]<>0 do rotate(i,father[i]);
          if right[i]<>0 then father[right[i]]:=0;
          right[i]:=0;
          fa[i]:=o;
          access(i);
        end;
    end;
end.

【上篇】
【下篇】

抱歉!评论已关闭.