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
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
23
动态树模板问题
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.